# Run with Docker

infinidysk ships as a single multi-arch image: `ghcr.io/infinidysk/infinidysk`. The container runs the frontend (public port `3000`) and backend (internal `8080`).

The examples use `:latest` (current stable). See [Release channels and tags](https://www.infinidysk.com/v1/getting-started/#release-channels-and-tags) for the `lts`, `rc`, and `dev` channels — and pin an exact version tag (`v1.2.3`) when you want reproducible deploys.

On IPv6-only hosts, `ghcr.io` is not reachable. Use the Docker Hub mirror `infinidysk/infinidysk` instead.

## Persistent Compose

```yaml
services:
  nzbdav:
    image: ghcr.io/infinidysk/infinidysk:latest
    container_name: nzbdav
    restart: unless-stopped
    healthcheck:
      test:
        - CMD-SHELL
        - curl -fsS http://localhost:3000/healthz > /dev/null || exit 1
      interval: 30s
      retries: 3
      start_period: 60s
      timeout: 5s
    ports:
      - "3000:3000"
    environment:
      PUID: "1000"
      PGID: "1000"
      TZ: America/New_York
    volumes:
      - ./config:/config
      - /mnt:/mnt
```

```bash
docker compose up -d
```

Set `PUID`/`PGID` from `id` on the host. Map `/mnt` (or your media paths) so completed downloads and library folders share paths with Arr and media servers.

The container fails startup before migrations if the config directory (`CONFIG_PATH`, default `/config`) is missing, is a file, or is not writable by `PUID`/`PGID`. Ownership repair is best-effort; ACLs and group-writable mounts are accepted when the runtime user can create and delete a probe file. The image already contains an empty `/config` directory, so a path existing inside the container is not proof a host volume is mounted. The frontend session key at `/config/session.key` is mode `0600`; if your supervisor repairs ownership using an allowlist, include that file without recursively chowning `blobs/`.

To manage Settings as code, use [`NZBDAV_CONFIG__...` variables](https://www.infinidysk.com/v1/configuration/headless/) <a class="since" href="https://github.com/infinidysk/infinidysk/releases/tag/v0.9.0">since 0.9.0</a>; see the [full Compose example](https://www.infinidysk.com/v1/configuration/headless/#fully-hydrated-compose-example).

## Change the published port

Compose port mappings use `HOST_PORT:CONTAINER_PORT`. To open infinidysk on port
`3001` without changing the ports inside the container:

```yaml
ports:
  - "3001:3000"
```

Open `http://your-server:3001`. Keep the container-side port at `3000`, including
the Compose healthcheck at `http://localhost:3000/healthz`. A mapping such as
`3001:3001` does not work unless the frontend is separately configured to listen
on `3001`.

With bridge networking, change only the host side of the mapping. Do not set `PORT` just to avoid a host port conflict.

### Host networking and internal port conflicts

With `network_mode: host`, there is no port mapping layer. Set `PORT` if the
frontend's port conflicts with another host service:

```yaml
network_mode: host
environment:
  PORT: "3001"
```

The backend remains on `8080`. If that port also conflicts, its listen URL and
the frontend's backend URL must change together:

```yaml
network_mode: host
environment:
  PORT: "3001"
  ASPNETCORE_URLS: "http://127.0.0.1:8081"
  BACKEND_URL: "http://127.0.0.1:8081"
```

Update the Compose healthcheck to use the effective frontend port
(`http://localhost:3001/healthz`) and update **Settings → General → Base URL**
when generated links should use the new public port.

:::note[DUMB deployments]
DUMB builds and launches infinidysk directly rather than using this image's
entrypoint. Change DUMB's `nzbdav.frontend_port` and
`nzbdav.backend_port` settings instead; DUMB supplies the corresponding
process environment automatically. See the
[DUMB infinidysk service guide](https://dumbarr.com/services/core/nzbdav/#configuration-in-dumb_configjson).
:::

## What the image does

1. Starts the frontend so maintenance progress can be shown.
2. Runs database migration / restore swap (`--db-migration`).
3. Starts the backend and waits for `/health` before considering startup complete.

Long one-time maintenance does not mark the Compose healthcheck unhealthy — it targets frontend `/healthz`.

## Reverse proxy

:::caution[TLS and WebSockets]
- Prefer HTTPS in front of port `3000`. Do not expose plain HTTP to the internet.
- Bind `127.0.0.1:3000:3000` when the proxy is on the Docker host.
- Allow HTTP Upgrade on **same-origin** `/ws` (Overview/Queue live updates).
- Set `SECURE_COOKIES=true` when the UI is HTTPS-only.
- Set **Base URL** in Settings to the public HTTPS address. It supplies STRM/adapter absolute URLs and lets same-origin UI actions such as login work through the proxy without `TRUST_PROXY`. It never blocks signing in directly over another address (for example `http://<lan-ip>:3000`); those requests use the standard same-origin check.
- Alternatively, enable **Trust reverse-proxy headers** <a class="since" href="https://github.com/infinidysk/infinidysk/releases/tag/v1.4.0">since 1.4.0</a> under **Settings → General** and have the proxy send correct `X-Forwarded-Host` and `X-Forwarded-Proto` headers. This is preferable when the public origin can vary. `TRUST_PROXY=1` enables and locks the same behavior from the container environment.
- For `addurl` to Docker-internal indexers, configure [Trusted local hosts](https://www.infinidysk.com/v1/configuration/sabnzbd/) or `TRUSTED_INTERNAL_HOSTS` <a class="since" href="https://github.com/infinidysk/infinidysk/releases/tag/v0.8.0">since 0.8.0</a>.
:::

## Optional environment

| Variable | Purpose |
|----------|---------|
| `TRUST_PROXY=1` | Enable and lock proxy `X-Forwarded-*` trust instead of using the General settings toggle |
| `TRUSTED_PROXY_CIDRS` | Widen backend proxy trust (split-container) |
| `TRUSTED_INTERNAL_HOSTS` <a class="since" href="https://github.com/infinidysk/infinidysk/releases/tag/v0.8.0">since 0.8.0</a> | Allowlist for private `addurl` targets |
| `SESSION_KEY` | Stable session secret (else persisted under `/config`) |
| `THREADPOOL_MIN_THREADS` / `THREADPOOL_MAX_THREADS` | Memory-constrained hosts |

Full list: [Environment variables](https://www.infinidysk.com/v1/configuration/environment-variables/).

## Next

[First run](https://www.infinidysk.com/v1/getting-started/first-run/) — admin account, providers, WebDAV, import strategy.