GICT knowledge base
How to Self-Host Docmost with Docker on Ubuntu 24.04
Published
Team documentation is easier to maintain when pages, search, and uploaded files live in one workspace. Docmost provides that workspace in a browser, with a collaborative editor and a Docker installation you can run on your own VPS.
This guide helps you install Docmost 0.96.0 with PostgreSQL and Redis on Ubuntu 24.04. It uses a private SSH tunnel rather than exposing the setup page to the internet.
Private-port prerequisite: use Docker Engine 28 or newer for the loopback-published ports in this guide. Older releases have a documented localhost-port exposure limitation. Confirm from another machine that the public IP cannot reach those private service ports; a proxy login does not protect a direct bypass route.
Before you start
Use an Ubuntu 24.04 VPS with working SSH access and a sudo-capable account. You also need an SSH client and a browser on your computer. The commands below use ubuntu as the server username; substitute your own login and replace SERVER_IP with the server address.
This is a private installation for access over SSH, not a public team portal. Each person connecting this way needs an authorized SSH route to the server. A hosted wiki is simpler if you do not want to operate the application and its database. Public HTTPS, email delivery, and enterprise features are outside this guide; password-reset email will not work until a mail provider is configured.
Docmost’s basic wiki and database search do not require an enterprise license. AI, SSO, and other licensed features are separate. Start with the ordinary page editor rather than treating every button in the interface as part of the free setup.
Install Docker and create the project
On a fresh Ubuntu server, install Docker and the Compose plugin from Ubuntu’s repositories:
$ sudo apt-get update
$ sudo apt-get install -y docker.io docker-compose-v2 curl openssl
$ sudo systemctl enable --now docker
$ sudo docker version
$ sudo docker compose version
If Docker is already installed from another source, keep that working installation rather than mixing package sources. Confirm that docker compose version works; the old standalone docker-compose command is not used here.
Create a new project directory under your account:
$ mkdir -p ~/docmost
$ cd ~/docmost
$ touch .env
$ chmod 600 .env
$ openssl rand -hex 32
$ openssl rand -hex 32
Use the first generated value for APP_SECRET and the second for POSTGRES_PASSWORD. Hexadecimal values avoid special characters that would need escaping in the database URL. Keep both values private.
Create ~/docmost/.env with these contents, replacing both placeholders with the generated values:
APP_SECRET=REPLACE_WITH_FIRST_HEX_VALUE
POSTGRES_PASSWORD=REPLACE_WITH_SECOND_HEX_VALUE
Keep the application secret stable. Do not regenerate it every time you start the containers.
Define the three services
Create ~/docmost/compose.yaml with the following contents. This follows the upstream three-service layout, with a pinned Docmost version and a loopback-only web port:
services:
docmost:
image: docmost/docmost:0.96.0
depends_on:
- db
- redis
environment:
APP_URL: http://localhost:18092
APP_SECRET: "${APP_SECRET}"
DATABASE_URL: "postgresql://docmost:${POSTGRES_PASSWORD}@db:5432/docmost"
REDIS_URL: redis://redis:6379
DISABLE_TELEMETRY: "true"
ports:
- "127.0.0.1:3000:3000"
restart: unless-stopped
volumes:
- docmost_data:/app/data/storage
db:
image: postgres:18
environment:
POSTGRES_DB: docmost
POSTGRES_USER: docmost
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
restart: unless-stopped
volumes:
- db_data:/var/lib/postgresql
redis:
image: redis:8
command: ["redis-server", "--appendonly", "yes", "--maxmemory-policy", "noeviction"]
restart: unless-stopped
volumes:
- redis_data:/data
volumes:
docmost_data:
db_data:
redis_data:
PostgreSQL holds the workspace and page records. The Docmost volume holds locally uploaded files, while Redis provides supporting application services. PostgreSQL 18 uses the /var/lib/postgresql volume mount shown here; do not substitute an older version’s data path without checking its image documentation.
Only the web service publishes a host port, and only on 127.0.0.1. PostgreSQL and Redis stay on the Compose network. APP_URL is the address the browser will use through the tunnel, not the server’s public IP.
Validate the configuration without printing the expanded secrets, then download and start the services:
$ sudo docker compose config --quiet
$ sudo docker compose pull
$ sudo docker compose up -d
$ sudo docker compose ps
$ curl -fsS http://127.0.0.1:3000/api/health
The first start initializes the database before the application is ready. If the health request fails immediately, wait briefly and retry it. An Up container alone does not prove that the application finished initialization. All three services should remain running, and the health endpoint should return a successful response before you continue.
For this example, the expected healthy response is shown below. Confirm it on your own instance, then complete the editor and attachment checks; health output alone is not an end-to-end test.
{"status":"ok","info":{"database":{"status":"up"},"redis":{"status":"up"}},"error":{},"details":{"database":{"status":"up"},"redis":{"status":"up"}}}
Open the private workspace
On your own computer, open a separate terminal and start the tunnel:
$ ssh -N -o ExitOnForwardFailure=yes -L 127.0.0.1:18092:127.0.0.1:3000 ubuntu@SERVER_IP
Leave that terminal open. In your browser, visit http://localhost:18092. The address is local to your computer; SSH carries the connection to the VPS. Do not browse to http://SERVER_IP:3000, which this configuration deliberately does not expose.
Complete the first-run form with a workspace name, your name, email address, and a strong password. This creates the workspace owner. Save the password before proceeding, since this installation has no email-based recovery configured.
When the workspace opens, select General, then New page. Give it a recognizable title, such as Operations notes, and add a sentence containing distinctive words, such as Amber lantern deployment checklist. The editor saves changes automatically; leave the page open until synchronization finishes.
Spaces organize pages within the workspace. Keep the test page private: do not enable public sharing just to make a link open in another browser.
Verify editing, search, and stored files
Open the same page in a second signed-in browser session. Add a short sentence in the first session and confirm that the second displays it without reloading. This exercises the editor’s live connection rather than only checking whether the login screen loads.
Open Search or press Ctrl+K. Leave Title only off to search inside pages, then enter the distinctive words you added. Newly edited text may not appear immediately; allow it to save and retry the search. Open the matching result and verify the text is present. Then search for an unrelated phrase to distinguish a real content match from simply reopening a recent page.
On an empty line in the editor, type /file, choose File attachment, and select a small test file. Once its name appears, hover over it and use the download icon. Compare the retrieved file with the original. Reopen the page after signing out and back in: its title, content, and uploaded file should still be available.
Finally, open the private page URL in a browser session that is not signed in. It should request authentication rather than reveal the page. A working local tunnel is only a network path; it should not bypass the workspace login.
If setup or editing does not work
On the VPS, return to the project directory and inspect the application logs:
$ cd ~/docmost
$ sudo docker compose logs --tail=80 docmost
- The application keeps restarting: check that both
.envvalues were replaced and that the application secret is at least 32 characters. Check database and Redis logs if the application cannot connect. Do not post expanded configuration or credentials in a public troubleshooting request. - The browser cannot connect: keep the SSH tunnel open and check for a local-port conflict. If you select a different local port, update
APP_URLto match and apply the configuration again withsudo docker compose up -d. - Pages open, but edits do not synchronize: the editor needs WebSockets. This direct SSH tunnel carries them without a reverse proxy. If you later introduce a proxy, verify its WebSocket support rather than assuming an HTTP page load proves it works.
- Uploads fail: inspect free disk space and the application logs. Keep the local-storage volume mounted at
/app/data/storage; an unmounted container directory is not persistent file storage.
You now have a private Docmost workspace with a working editor, searchable pages, and stored files. Keep the terminal tunnel open while using it; closing the tunnel disconnects your browser without stopping Docmost on the VPS.
Reference: Docmost installation. Check the documentation for your installed version before applying changes.
Related guides
How to Self-Host DocuSeal for Document Signing
Self-host DocuSeal with private administrator setup, PostgreSQL and HTTPS. Test signing, understand email data flows and create consistent backups.
Self HostedHow to Remove Image Backgrounds Locally with rembg
Remove image backgrounds locally with rembg. Preserve originals, check PNG transparency and inspect cutout quality on both light and dark backgrounds.
Self HostedHow to Translate Text Offline with Argos Translate
Translate plain text locally with Argos Translate. Install a language pair, prepare caches, verify offline operation and review translation quality.
Self HostedHow to Self-Host Vikunja with Docker on Ubuntu 24.04
Self-host Vikunja with Docker and PostgreSQL. Create an account privately, connect through SSH and verify tasks, attachments and persistent storage.
