> ## Documentation Index
> Fetch the complete documentation index at: https://docs.minestorecms.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Docker Installation

> Install MineStoreCMS as a Docker or Podman container — an alternative to the bare-metal installer for users who prefer container workflows or need multi-instance hosting on a single VPS.

## **Introduction**

The **Docker install path** is an additional way to install MineStoreCMS alongside the bare-metal **[installer.sh](/installation/installation)**. It packages the full stack (nginx, php-fpm, Next.js, workers, scheduler, Discord bot) into a single application container that talks to a separate **MariaDB** container.

<Check>
  Docker mode supports **multiple isolated instances** on the same VPS out of the box — useful if you host more than one store from a single server.
</Check>

<Info>
  Both **Docker** and **Podman** runtimes are supported. The installer auto-detects which one you have and uses the appropriate `compose` command.
</Info>

## **Requirements**

* A VPS running **Ubuntu 22.04+ / Debian 12+** or **RHEL 9 / Rocky 9 / AlmaLinux 9**.
* Root access (or a user with `sudo`).
* A valid **MineStoreCMS license key**.
* Optional but recommended: a domain pointing to your VPS for SSL.

The installer pulls in **Docker 20.10+** (or **Podman 4.x+**) and the `compose` plugin automatically as part of the dependency step below.

## **Installation**

The installer is a **6-step interactive wizard**: instance name → license → domain → reverse-proxy choice → DB mode → confirm.

<Steps>
  <Step title={'Connect to Your VPS'}>
    SSH into your VPS as `root` or a user with `sudo` privileges.
  </Step>

  <Step title={'Install Dependencies'}>
    <Tabs>
      <Tab title="Ubuntu / Debian">
        ```bash theme={null}
        sudo apt-get update
        sudo apt-get install -y \
            git docker.io docker-compose-plugin \
            gettext-base iproute2 curl
        sudo systemctl enable --now docker
        ```
      </Tab>

      <Tab title="RHEL / Rocky / Alma">
        ```bash theme={null}
        sudo dnf install -y \
            git docker docker-compose-plugin \
            gettext iproute curl
        sudo systemctl enable --now docker
        ```
      </Tab>
    </Tabs>

    <Info>
      `gettext` / `gettext-base` provides `envsubst`, which the installer uses to render the `docker-compose.yaml` template. `iproute2` provides `ss`, used for port-collision checks.
    </Info>
  </Step>

  <Step title={'Clone the Container Repo'}>
    ```bash theme={null}
    sudo git clone https://github.com/MineStoreCMS/minestorecms-container.git /srv/minestorecms-src
    ```
  </Step>

  <Step title={'Run the Installer'}>
    ```bash theme={null}
    cd /srv/minestorecms-src
    sudo bash installers/docker-installer.sh
    ```
  </Step>

  <Step title={'Follow the Wizard'}>
    Enter the **instance name** (e.g. `greencraft`), your **license key**, the **domain** you want to use, and pick a **reverse-proxy** option (see below).
  </Step>

  <Step title={'Wait for the Build'}>
    The first build takes **3–5 minutes** — the image fetches the tarball for your license, installs system packages, Composer dependencies and the frontend.
  </Step>

  <Step title={'Open the Admin Panel'}>
    Once the wizard finishes, open `https://<your-domain>/admin` and complete the in-browser setup.
  </Step>
</Steps>

<Info>
  **Need SSL via Let's Encrypt?** If you plan to pick the `certbot` option in the wizard, install `certbot` and the matching plugin first:

  ```bash theme={null}
  # Nginx
  sudo apt-get install -y certbot python3-certbot-nginx
  # Apache
  sudo apt-get install -y certbot python3-certbot-apache
  ```

  Caddy and "Install Caddy" options issue certs automatically — no `certbot` needed.
</Info>

## **Reverse-Proxy Options**

The installer can generate a host-level vhost for several web servers, or skip proxying entirely if you handle TLS upstream (e.g. Cloudflare).

| **Option**        | **Best for**                                                                                 |
| ----------------- | -------------------------------------------------------------------------------------------- |
| **Caddy**         | The simplest option — auto-issues a Let's Encrypt certificate, no extra steps.               |
| **Install Caddy** | If no web server is running, the installer installs Caddy and configures it.                 |
| **Nginx**         | Generates an `nginx` vhost and runs `certbot --nginx -d <domain>` if you choose certbot SSL. |
| **Apache2**       | Generates an `apache2` vhost and runs `certbot --apache -d <domain>` if you choose certbot.  |
| **Skip**          | The container only binds to `127.0.0.1:<HTTP_PORT>` — route to it from your own proxy.       |

<Info>
  When the host **already runs** a web server, the installer detects it and marks that option as **(Recommended)** — pressing Enter accepts the recommendation.
</Info>

## **Day-2 Operations — `minestore` CLI**

After installation, the host exposes a `minestore` command for ongoing operations.

```bash theme={null}
sudo minestore list                       # all instances on this host
sudo minestore status   <name>            # container health
sudo minestore logs     <name> [service]  # tail container logs
sudo minestore artisan  <name> <cmd>      # run any artisan command
sudo minestore update   <name>            # rebuild image + restart (preserves data)
sudo minestore backup   <name>            # tarball of all volumes + db dump
sudo minestore restore  <name> --from <file>
sudo minestore destroy  <name>            # remove one instance
sudo minestore uninstall                  # remove ALL instances and the CLI
sudo minestore proxy    create|regenerate|remove|list
sudo minestore install-systemd <name>     # autostart units (Podman)
```

## **Multi-Instance Hosting**

Each instance lives under `/opt/minestore/<name>/` with its own `docker-compose.yaml`. Compose project names are auto-prefixed as `minestore-<name>`, so containers, networks and volumes from different instances **never collide**.

**Example — running GreenCraft and RedCraft on the same VPS:**

```bash theme={null}
sudo minestore create greencraft     # picks port 80 if free
sudo minestore create redcraft       # offers a high port (e.g. 18001) or
                                     # installing Caddy as a shared front-end
```

<Info>
  The first instance takes port `80` by default. The installer offers to install Caddy and route by domain for subsequent instances.
</Info>

## **Updating**

```bash theme={null}
sudo minestore backup <name>
sudo minestore update <name>
```

`update` runs `compose build --no-cache` — the image fetches the latest tarball for your license, the entrypoint runs `artisan migrate --force`, and the frontend is rebuilt only when `package.json` actually changed. All persistent state (database, `.env`, uploads, installed theme) survives the rebuild because it lives in **named volumes**.

<Warning>
  Auto-update via the admin **"Upgrade"** button is **disabled** in Docker mode — it would write to the immutable image layer. Use `sudo minestore update <name>` from the host instead.
</Warning>

## **Persistent Data**

The following volumes survive container rebuilds:

| **Volume**   | **Contents**                                          |
| ------------ | ----------------------------------------------------- |
| `env`        | Your Laravel `.env` file.                             |
| `storage`    | Laravel `storage/` (logs, sessions, framework cache). |
| `pub-img`    | User-uploaded images under `public/img/`.             |
| `pub-assets` | Theme assets and other generated files.               |
| `frontend`   | Installed frontend (default theme or a third-party).  |
| `db-data`    | MariaDB data directory.                               |

## **Backups**

`minestore backup <name>` creates a single tarball containing:

* An atomic snapshot of every named volume above.
* A `mysqldump` of the database.

Restore with `minestore restore <name> --from <file>`. The restore replaces the current state — back up beforehand if you want to keep it.

## **Podman Notes**

<Warning>
  **Rootful Podman** is recommended (`sudo bash docker-installer.sh`). Rootless Podman cannot bind to privileged ports (80/443) without:

  ```bash theme={null}
  sudo sysctl net.ipv4.ip_unprivileged_port_start=80
  ```
</Warning>

* `HEALTHCHECK` is preserved because the installer passes `--format=docker` to `podman compose build`.
* For boot-time autostart: `sudo minestore install-systemd <name>` generates Podman systemd units under `/etc/systemd/system/`.
* **SELinux** — the default named volumes are unaffected by SELinux labels. If you switch to bind mounts, append `:Z` to each mount.

## **Troubleshooting**

<CardGroup cols="1">
  <Card title="App container is unhealthy" icon="heart-pulse">
    Run `sudo minestore logs <name>`. The most common causes are: the DB container not yet ready, an invalid license key, or first-run `pnpm install` timing out on a slow disk.
  </Card>

  <Card title="certbot fails to issue a certificate" icon="lock-open">
    DNS for the domain is not yet pointing to the host, or port 80 is firewalled. Fix DNS and then `sudo minestore proxy regenerate <name>`.
  </Card>

  <Card title="Admin 'Upgrade' button returns an error" icon="ban">
    Expected — auto-update is disabled in container mode. Run `sudo minestore update <name>` from the host instead.
  </Card>

  <Card title="Update doesn't apply" icon="rotate">
    Confirm `compose build` actually re-fetched the tarball — `--no-cache` is used automatically by `minestore update`. Verify the running version with `sudo minestore artisan <name> "about"`.
  </Card>
</CardGroup>

## **Next Steps**

<CardGroup cols={2}>
  <Card title="Webstore Setup" icon="gear" href="/installation/configuration">
    Configure your webstore by following the post-install setup.
  </Card>

  <Card title="Minecraft Server Connection" icon="plug" href="/installation/minecraft-server">
    Install the plugin or use RCON to connect your Minecraft server.
  </Card>
</CardGroup>
