Skip to content

Self host on an Ubuntu server

Alien edited this page Oct 18, 2026 · 1 revision

Put Dossier on a server of your own, from a fresh Ubuntu to Dossier on your domain with HTTPS: Docker Compose runs the app and PostgreSQL, and Caddy serves it over HTTPS. These are the README's Self-hosting steps with Ubuntu's details filled in, including a firewall. To run it without Docker, see Without Docker at the end.

What you need

  • A server with Ubuntu 24.04 LTS or newer, on an Intel or AMD processor (x86-64). The image isn't built for ARM servers.
  • At least 2 vCPUs and 2 GB of memory, and a few GB of disk. A local model needs much more: see Get a VPS in the README.
  • A domain name, such as dossier.example.com, with a DNS A record pointing at the server's address (and an AAAA record if it has an IPv6 one).
  • SSH access as a user who can use sudo.

1. Prepare the server

Bring the system up to date:

sudo apt update && sudo apt upgrade -y

Open only SSH and the web. ufw comes with Ubuntu; allow SSH before you turn it on, or you'll lock yourself out:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 443/udp
sudo ufw enable

Ports 80 and 443 are for Caddy, which gets the certificate and serves HTTPS (UDP 443 is for HTTP/3). Ports that Docker publishes skip ufw, so ufw can't close them. The Compose file only publishes Dossier on the server itself (127.0.0.1), so leave its ports entry as it is.

2. Install Docker

Docker's install script sets up Docker Engine and the Compose plugin:

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER

The last line lets you run docker without sudo (membership in the docker group is as good as root, so only add accounts you trust). Log out and back in for it to apply, then check that docker compose version answers. To install it by hand instead, see Docker's guide for Ubuntu.

3. Set up Dossier

Make a folder for Dossier, fetch the Compose file into it, and put the database password, DOSSIER_SECRET and your time zone in .env (put your own time zone in the fifth line):

mkdir ~/dossier && cd ~/dossier
curl -fsSL -o compose.yml https://raw.githubusercontent.com/AienTech/dossier/main/compose.production.yml
echo "POSTGRES_PASSWORD=$(openssl rand -hex 24)" > .env
echo "DOSSIER_SECRET=$(openssl rand -base64 32)" >> .env
echo "TZ=Europe/Berlin" >> .env
chmod 600 .env

Then make a hash of the password you'll sign in with. Type it twice; the command prints one line that starts with argon2id::

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

Add it to .env as DOSSIER_PASSWORD=argon2id:…, with nano .env. What these variables are for, and every other one: Environment variables in the README.

Start Dossier and watch it come up:

docker compose up -d
docker compose logs -f app

On every start, Dossier applies the database migrations and loads its built-in themes before it serves. Once the log says Ready, press Ctrl+C. curl -s localhost:3000/api/health now answers {"status":"ok", …}.

4. Turn on HTTPS

Dossier only listens on the server itself, so put Caddy in front of it. Caddy gets a certificate for your domain and renews it on its own. Install it, and replace its default configuration with your domain:

sudo apt install -y caddy
sudo tee /etc/caddy/Caddyfile > /dev/null <<'EOF'
dossier.example.com {
    reverse_proxy localhost:3000
}
EOF
sudo systemctl reload caddy

Open https://dossier.example.com and sign in. If the page doesn't load, sudo journalctl -u caddy says why; most often the DNS record doesn't point at the server yet, or port 80 is closed.

To use nginx or another proxy instead, see "Another proxy, or no HTTPS at home" under Set up the app in the README: Dossier needs a few headers from it.

5. After installing

Without Docker

Dossier can also run straight on the server with Node.js, as a systemd service behind the same Caddy. You build it yourself, and build it again for each upgrade.

  1. Do step 1 above.

  2. Follow Run locally with Node.js steps 1 to 5, as your own user, with the code in ~/dossier.

  3. Make Dossier a service that starts with the server and restarts if it stops:

    sudo tee /etc/systemd/system/dossier.service > /dev/null <<EOF
    [Unit]
    Description=Dossier
    After=network-online.target postgresql.service
    Wants=network-online.target
    
    [Service]
    User=$USER
    WorkingDirectory=$HOME/dossier
    Environment=HOSTNAME=127.0.0.1 PORT=3000
    ExecStart=/usr/bin/node .next/standalone/server.js
    Restart=on-failure
    MemoryMax=1G
    
    [Install]
    WantedBy=multi-user.target
    EOF
    sudo systemctl daemon-reload
    sudo systemctl enable --now dossier

    journalctl -u dossier -f follows its log.

  4. Do step 4 above for HTTPS.

Day to day:

  • Change a setting: edit ~/dossier/.env, then copy it to where the server reads it, and restart:

    cp ~/dossier/.env ~/dossier/.next/standalone/
    sudo systemctl restart dossier
  • Back up: take dumps as under Day to day in the Node.js guide. To restore one, stop Dossier first:

    sudo systemctl stop dossier
    sudo -u postgres pg_restore --clean --if-exists -d dossier < dossier.dump
    sudo systemctl start dossier
  • Upgrade: run sudo systemctl stop dossier, then the Upgrade commands under Day to day and every command in step 5 of the Node.js guide (not step 6). Then start it again with sudo systemctl start dossier.

Clone this wiki locally