---
verify:
  preset: debian-13-vm
  run_as: user
  blocks: [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 13, 14, 30, 31, 32, 34]
  signal:
    type: http
    url: http://localhost:3000
    expect_status: 200
---

# Install Docmost on a Debian VM with Docker Compose

This guide installs [Docmost](https://docmost.com/) on a Debian 12 VM using Docker Compose. It covers Docker installation, a production-ready Compose setup, optional Nginx and HTTPS, backups, and upgrades.

## Prerequisites

- Debian 12 (Bookworm) or Debian 11 VM
- A user with `sudo` access
- 2 vCPU, 2 GB RAM, and at least 20 GB disk space recommended
- Optional: a domain name pointing to the VM, for example `docs.example.com`
- Open firewall ports: `22` for SSH, and either `3000` for direct access or `80`/`443` when using a reverse proxy

## 1. Update Debian and install prerequisites

```bash
sudo apt update
sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg
```

## 2. Install Docker Engine and Docker Compose

Add Docker’s official GPG key:

```bash
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
```

Add the Docker apt repository:

```bash
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
```

Install Docker Engine and the Compose plugin:

```bash
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
```

Verify the installation:

```bash
sudo docker run hello-world
docker compose version
```

Optional: run Docker as your non-root user.

```bash
sudo usermod -aG docker $USER
newgrp docker
```

Log out and back in if `newgrp` does not take effect in your current session.

## 3. Create the Docmost directory and `.env`

```bash
sudo mkdir -p /opt/docmost
sudo chown -R $USER:$USER /opt/docmost
cd /opt/docmost
```

Generate secrets:

```bash
openssl rand -hex 32
openssl rand -hex 24
```

Use the first value for `APP_SECRET` and the second for `POSTGRES_PASSWORD`.

Create the `.env` file:

```bash
nano .env
```

Example content:

```dotenv:.env
APP_URL=http://203.0.113.10:3000
APP_SECRET=replace_with_openssl_rand_hex_32
POSTGRES_DB=docmost
POSTGRES_USER=docmost
POSTGRES_PASSWORD=replace_with_openssl_rand_hex_24
```

Replace `203.0.113.10` with your VM’s public IP or domain name. Keep `APP_SECRET` stable and private.

Secure the file:

```bash
chmod 600 .env
```

## 4. Create the Docker Compose file

Create `compose.yaml`:

```bash
nano compose.yaml
```

Paste the following:

```yaml:compose.yaml
services:
  docmost:
    image: docmost/docmost:latest
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      APP_URL: ${APP_URL}
      APP_SECRET: ${APP_SECRET}
      DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public
      REDIS_URL: redis://redis:6379
    ports:
      - "3000:3000"
    restart: unless-stopped
    volumes:
      - docmost_data:/app/data/storage

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  docmost_data:
  db_data:
  redis_data:
```

If your database password contains characters such as `@`, `:`, `/`, or `#`, use a hex password as shown above or URL-encode the password in `DATABASE_URL`.

## 5. Start Docmost

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

Check containers and logs:

```bash
docker compose ps
docker compose logs -f docmost
```

Open `http://YOUR_VM_IP:3000` and complete the initial setup to create the first admin account.

If you use UFW and access Docmost directly:

```bash
sudo ufw allow OpenSSH
sudo ufw allow 3000/tcp
sudo ufw enable
```

## 6. Optional: Nginx reverse proxy and HTTPS

Install Nginx and Certbot:

```bash
sudo apt install -y nginx certbot python3-certbot-nginx
```

Create the Nginx site configuration:

```bash
sudo nano /etc/nginx/sites-available/docmost
```

Paste the following, replacing `docs.example.com` with your domain:

```nginx
server {
    listen 80;
    server_name docs.example.com;

    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
    }
}
```

Enable the site and reload Nginx:

```bash
sudo ln -s /etc/nginx/sites-available/docmost /etc/nginx/sites-enabled/docmost
sudo nginx -t
sudo systemctl reload nginx
```

Obtain an HTTPS certificate:

```bash
sudo certbot --nginx -d docs.example.com
```

Update `.env`:

```dotenv
APP_URL=https://docs.example.com
```

Restart Docmost:

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

For better security, make Docmost listen only on localhost when using a reverse proxy. Change the port mapping in `compose.yaml` from:

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

to:

```yaml
    ports:
      - "127.0.0.1:3000:3000"
```

Then restart:

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

## 7. Optional: email and SMTP

Docmost uses SMTP for invitations, password resets, and notifications. Add these values to `.env`:

```dotenv
MAIL_DRIVER=smtp
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=user@example.com
SMTP_PASSWORD=your-smtp-password
SMTP_SECURE=false
MAIL_FROM_ADDRESS=docmost@example.com
MAIL_FROM_NAME=Docmost
```

Add the matching variables to the `docmost.environment` section in `compose.yaml`:

```yaml
      MAIL_DRIVER: ${MAIL_DRIVER}
      SMTP_HOST: ${SMTP_HOST}
      SMTP_PORT: ${SMTP_PORT}
      SMTP_USERNAME: ${SMTP_USERNAME}
      SMTP_PASSWORD: ${SMTP_PASSWORD}
      SMTP_SECURE: ${SMTP_SECURE}
      MAIL_FROM_ADDRESS: ${MAIL_FROM_ADDRESS}
      MAIL_FROM_NAME: ${MAIL_FROM_NAME}
```

Restart Docmost:

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

Use `SMTP_SECURE=true` for port `465`. Use `SMTP_SECURE=false` for port `587`.

## 8. Backups

Create a backup directory:

```bash
mkdir -p /opt/docmost/backups
cd /opt/docmost
```

Back up the database:

```bash
docker compose exec -T db pg_dump -U docmost docmost > "backups/docmost-db-$(date +%F).sql"
```

Find the Docmost storage volume name:

```bash
docker volume ls | grep docmost
```

Example output:

```text
local     docmost_docmost_data
```

Back up the storage volume using the name from the previous command:

```bash
docker run --rm \
  -v docmost_docmost_data:/data \
  -v "$PWD/backups:/backup" \
  alpine tar czf "/backup/docmost-storage-$(date +%F).tar.gz" -C /data .
```

Restore the database:

```bash
cat backups/docmost-db-2025-01-01.sql | docker compose exec -T db psql -U docmost docmost
```

Stop Docmost before restoring the storage volume.

## 9. Upgrade Docmost

Back up first, then run:

```bash
cd /opt/docmost
docker compose pull
docker compose up -d
docker compose logs -f docmost
```

## 10. Troubleshooting

- Check logs:

  ```bash
  docker compose logs -f docmost
  docker compose logs -f db
  docker compose logs -f redis
  ```

- `docker compose` command not found: install the `docker-compose-plugin` package.

- Permission denied when running Docker: add your user to the `docker` group and log out and back in.

  ```bash
  sudo usermod -aG docker $USER
  ```

- Port `3000` is already in use: change the port mapping to `127.0.0.1:3000:3000` or another available port.

- Database connection errors: verify `POSTGRES_DB`, `POSTGRES_USER`, and `POSTGRES_PASSWORD` in `.env`. The database hostname in `DATABASE_URL` must be `db`, not `localhost`.

- Incorrect links, redirects, or login issues: confirm `APP_URL` matches the public URL exactly, including `https://` and without a trailing slash, then restart Docmost.

- WebSocket or real-time collaboration issues behind Nginx: ensure the `Upgrade` and `Connection` headers are present in the Nginx configuration.

- Email not sending: verify SMTP settings and restart Docmost.

- Reset all data, including the database and storage volumes:

  ```bash
  docker compose down -v
  ```

  This is destructive and cannot be undone.

## 11. Uninstall

Stop and remove the containers:

```bash
cd /opt/docmost
docker compose down
```

Remove the database and storage volumes:

```bash
docker compose down -v
```

Remove the directory:

```bash
sudo rm -rf /opt/docmost
```

## Security notes

- Keep `.env` private and use `chmod 600 .env`.
- Do not expose PostgreSQL or Redis ports. The Compose file keeps them internal to the Docker network.
- Use HTTPS in production.
- Keep `APP_SECRET` stable and secret. Changing it can invalidate sessions.
- Run regular database and storage backups.