Skip to content

Self Hosting

bitbiter-dev edited this page May 7, 2026 · 4 revisions

Self-Hosting

Prerequisites

  • Docker and Docker Compose
  • A folder of photos and videos accessible as a host path
  • Optional: Intel, NVIDIA, or AMD GPU for hardware-accelerated video transcoding

Quick start

# 1. Copy the environment template
cp src/.env.example src/.env

# 2. Fill in your values (see Configuration reference below)
#    Required: DB_PW, WORKER_USER

# 3. Edit docker-compose.yml — replace the placeholder NAS path:
#    /path/to/your/nas  →  your actual mount path

# 4. Start all containers
docker-compose -f src/docker-compose.yml up -d

The API is available on port 8080.


Multi-user setup

A single Worker handles all users by default. No extra configuration is needed — the Worker discovers all registered users and their NAS paths from the database on startup, then crawls each in round-robin order.

Each user's NAS folder must be mounted into the single Worker container. If all users share one NAS root, one mount is enough:

anichron-worker:
  volumes:
    - /nas:/data/originals:ro          # all users' folders under one root
    - ${BASE_PATH}/anichron/proxy_cache:/data/proxies:rw

If users have separate NAS roots, mount them as subdirectories:

anichron-worker:
  volumes:
    - /nas/alice:/data/originals/alice:ro
    - /nas/bob:/data/originals/bob:ro
    - ${BASE_PATH}/anichron/proxy_cache:/data/proxies:rw

Dedicated Worker for one user (optional): Set WORKER__USER on a Worker container to pin it to a specific user. This is useful when one user has a very large library and needs a dedicated processor:

anichron-worker-alice:
  environment:
    - WORKER__USER=alice@example.com
  volumes:
    - /nas/alice:/data/originals:ro
    - ${BASE_PATH}/anichron/proxy_cache:/data/proxies:rw

Each NAS path must belong to exactly one user — sharing a path between users is not supported. See Deployment Decisions and ADR-12 for the rationale.


GPU acceleration

The Worker detects available hardware at startup and selects the best encoder automatically:

  1. Intel QuickSync (h264_qsv) — requires /dev/dri passthrough
  2. NVIDIA NVENC (h264_nvenc) — requires NVIDIA runtime
  3. AMD AMF (h264_amf) — requires AMD GPU
  4. Software (libx264) — always available, no hardware required

If you have no Intel GPU, remove the devices block from the worker service in docker-compose.yml. The Worker falls back to software encoding without error. See Deployment Decisions for details.


Rate limiting

The API applies a built-in sliding-window rate limit (10 requests / 60 seconds per IP) to the login and registration endpoints. For stronger protection — especially against distributed attacks — configure rate limiting at your reverse proxy as well.


Cross-origin deployment

If your UI and API run on different origins (e.g. UI on app.example.com, API on api.example.com), configure the allowed origins on the API container. The API uses indexed ASP.NET Core array binding:

environment:
  - Cors__AllowedOrigins__0=https://app.example.com
  - Cors__AllowedOrigins__1=https://localhost:3000   # optional second origin

When at least one origin is configured:

  • The API sends the correct Access-Control-Allow-Origin header
  • The refresh token cookie switches from SameSite=Strict to SameSite=None automatically (required for cross-origin cookie sending; still HttpOnly and Secure)
  • AllowCredentials is enabled on the CORS policy so the browser attaches the cookie

Leave all Cors__AllowedOrigins__* unset when using a reverse proxy on the same origin — the API defaults to SameSite=Strict which provides stronger CSRF protection and does not require a CORS policy.


Bootstrap admin

On first startup, if the database contains no users, the API automatically creates a bootstrap admin account. The username and password are read from environment variables:

Variable Default Notes
BOOTSTRAP_ADMIN_USERNAME admin Stored lowercased
BOOTSTRAP_ADMIN_PASSWORD admin Must be changed on first login

If either variable is absent, the defaults (admin / admin) are used and a warning is logged. The account is created with MustChangePassword = true regardless.

Recommended setup:

environment:
  - BOOTSTRAP_ADMIN_USERNAME=yourname
  - BOOTSTRAP_ADMIN_PASSWORD=a-strong-random-password

Remove or clear both variables after the admin account is created — they are only read when no users exist.


Admin password reset

If you lose access to the admin account, set ADMIN_RESET_PASSWORD on the API container and restart:

environment:
  - ADMIN_RESET_PASSWORD=new-password

On startup the API resets the password and sets MustChangePassword = true. A warning is logged. Remove the variable immediately after logging in — it is applied on every restart while set.

If exactly one admin account exists, it is reset automatically.

If multiple admin accounts exist, you must also set ADMIN_RESET_USERNAME to identify the target. Without it the API logs an error and skips the reset entirely:

environment:
  - ADMIN_RESET_PASSWORD=new-password
  - ADMIN_RESET_USERNAME=alice

Configuration reference

app.ini and environment variables

On first startup the API generates configuration/app.ini inside the container's working directory. The JWT signing secret is auto-generated and written there — no manual secret generation is required.

Any setting listed below can be placed in app.ini instead of (or alongside) environment variables. Environment variables always take precedence over app.ini values.

Required variables

Variable Description
DB_PW PostgreSQL password for the anichron_admin database user
WORKER__USER Email or username of the user this Worker instance processes

API environment variables

Variable Default Description
Cors__AllowedOrigins__0 (unset) First allowed UI origin (e.g. https://app.example.com). Add __1, __2, … for additional origins
Jwt__AccessTokenMinutes 15 Access token lifetime in minutes
Jwt__RefreshTokenDays 60 Refresh token lifetime in days
BOOTSTRAP_ADMIN_USERNAME admin Username for the bootstrap admin created on first startup (empty DB only)
BOOTSTRAP_ADMIN_PASSWORD admin Password for the bootstrap admin. Sets MustChangePassword = true
ADMIN_RESET_PASSWORD (unset) Resets the target admin's password on every startup until removed
ADMIN_RESET_USERNAME (unset) Required when multiple admin accounts exist; identifies which admin to reset

Worker environment variables

Variable Default Description
WORKER__USER (required) Email or username of the user this Worker belongs to
WORKER__ROOT /data/originals Root path inside the container to scan for media
WORKER__CRAWL_INTERVAL_HOURS 4 How often to run a full NAS crawl, in hours
WORKER__MAX_CONCURRENT_FILES 4 Maximum number of files to process in parallel