Skip to content

Self host with CapRover

Alien edited this page Oct 18, 2026 · 1 revision

Run Dossier on a CapRover server: one app from the published image, next to CapRover's PostgreSQL one-click app. CapRover's nginx serves it over HTTPS.

What you need

  • A CapRover server with its root domain set up (a wildcard DNS record, such as *.apps.example.com). To start one, see CapRover's getting started guide. These steps are for CapRover 1.15.
  • At least 2 vCPUs and 2 GB of memory, on an Intel or AMD processor (x86-64): Dossier needs about 1 GB, PostgreSQL and CapRover the rest. The image isn't built for ARM servers. A local model needs much more: see Get a VPS in the README.

1. Create the database

Apps → One-Click Apps/Databases → PostgreSQL. Name it dossier-db, set the version to 18, and set a user, a long random password (openssl rand -hex 24 makes one) and the database name dossier.

Other apps reach it at srv-captain--dossier-db:5432. Leave its port unmapped, so it isn't reachable from outside.

2. Create the app

Apps → Create a New App, named dossier, with Has Persistent Data ticked. Then, in the app's settings:

  • App Configs → Environment Variables: switch to Bulk Edit and enter:

    DATABASE_URL=postgresql://<user>:<password>@srv-captain--dossier-db:5432/dossier
    DOSSIER_SECRET=<32 or more random characters>
    DOSSIER_PASSWORD=<a hash of the password you'll sign in with>
    

    openssl rand -base64 32 makes a secret. For the hash, run this on the server, or anywhere with Docker, type your password twice, and paste the line it prints, which starts with argon2id::

    docker run --rm -it ghcr.io/aientech/dossier hash-password

    Add TZ with your time zone, such as TZ=Europe/Berlin. Every variable is in Environment variables in the README.

  • App Configs → Persistent Directories: path in app /data, label dossier-data. Nightly backups and zipped PDFs go there.

  • App Configs → Instance Count: leave it at 1. Dossier runs its nightly backups, AI tasks and PDF printing inside its own process, so a second instance would do some of it twice.

  • App Configs → Service Update Override: a memory limit that leaves room for Chromium, and updates that start the new version before stopping the old one, and go back to it if the new one doesn't come up healthy (for example when a migration fails):

    TaskTemplate:
      Resources:
        Limits:
          MemoryBytes: 1073741824
    UpdateConfig:
      Order: start-first
      FailureAction: rollback
  • HTTP Settings → Container HTTP Port: 3000.

Press Save & Restart.

3. Deploy

In the app's Deployment tab, under Deploy via ImageName, enter ghcr.io/aientech/dossier:latest as the Image Name and press Deploy Now. Or enter a version such as ghcr.io/aientech/dossier:v1.6.0, to upgrade only when you choose. The image is public, so CapRover pulls it without signing in.

On every start, Dossier applies the database migrations and loads its built-in themes before it serves; the Deployment tab's app logs show each step. When it's up, http://dossier.<your root domain>/api/health answers {"status":"ok", …}.

4. Turn on HTTPS

In the app's HTTP Settings, connect your own domain if you like, then press Enable HTTPS and tick Force HTTPS by redirecting all HTTP traffic to HTTPS. Save, open the address and sign in.

Dossier relies on the headers CapRover's nginx sets: X-Forwarded-Proto, and the visitor's address added to X-Forwarded-For. So leave Port Mapping empty: requests that reach the container without going through nginx could set those headers themselves. Its default upload limit, 500 MB, is plenty for imports.

5. Optional: Ollama for a local model

With a local model, your profile and documents never leave your server. Ollama can run as a second CapRover app:

  1. Apps → Create a New App named ollama, with Has Persistent Data ticked.

  2. App Configs → Persistent Directories: path in app /root/.ollama, label ollama-models, so models survive updates. Set Instance Count to 1, and give it room with a Service Update Override (8 GB for qwen2.5:7b):

    TaskTemplate:
      Resources:
        Limits:
          MemoryBytes: 8589934592
  3. HTTP Settings: tick Do not expose as web-app. Dossier reaches it inside CapRover; nothing else should.

  4. Deployment → Deploy via ImageName: ollama/ollama:0.34.4.

  5. Pull a model. On the server, run:

    docker exec -it $(docker ps -q -f name=ollama) ollama pull qwen2.5:7b
  6. In Dossier, open Settings → AI provider → Local model, set the server address to http://srv-captain--ollama:11434, pick the model and press Test connection.

Which model to pick, and how fast it is: Local model with Ollama.

Day to day

  • Change a setting: edit the app's environment variables and press Save & Restart.

  • Back up: export from Settings → Your data, and take database dumps. On the server, docker ps --format '{{.Names}}' lists the containers. Dossier's name starts with dossier. (or srv-captain--dossier. for apps made before CapRover 1.15), the database's with dossier-db. (or srv-captain--dossier-db.). Then:

    docker exec <the database's container> pg_dump -U <user> -Fc dossier > dossier.dump
    docker cp <Dossier's container>:/data/backups ./backups

    To restore a dump, stop Dossier with docker service scale <its service>=0 (docker service ls shows its name), load the dump, and scale it back to 1:

    docker exec -i <the database's container> pg_restore --clean --if-exists -U <user> -d dossier < dossier.dump

    More in Backups and restore.

  • Upgrade: take an export and a database dump first, then deploy the new version under Deploy via ImageName; with latest, deploy ghcr.io/aientech/dossier:latest again. With the Service Update Override above, the old version keeps serving until the new one is healthy. See Upgrading.

  • Something's wrong: the app logs in the Deployment tab, and Troubleshooting.

Clone this wiki locally