Skip to content

How to Deploy Wiki.js on a VPS

Updated Sep 2026

verified on Ubuntu 26.04 · Sep 2026
We earn commissions when you shop through the links below. Full disclosure →

Self-host Wiki.js 2 on a small VPS with PostgreSQL, HTTPS through Caddy, a locked-down setup wizard, and database backups you can restore.

Before you start
  • A VPS with at least 1 GB RAM (the Wiki.js documented minimum on Linux)
  • A fresh Ubuntu 24.04 or 26.04 server with root/sudo SSH access
  • A dedicated domain or subdomain — Wiki.js can't be served from a subfolder
  • Docker Engine + Compose installed (see the base guide below)
Need a box for this guide? Kamatera's free tier lets you spin one up now.Start free on Kamatera → (opens in new tab)

What Wiki.js is

Wiki.js is a Node.js wiki released under the AGPL-3.0 licence. You write pages in Markdown or a visual editor, organize them by path, and control who can read or edit what with groups and page rules. Its authentication modules are unusually broad for a free build: local accounts, social logins, and enterprise options such as LDAP, SAML, OIDC and CAS are all included, with optional two-factor authentication.

Wiki.js brings its own web server but no database — you run one next to it. PostgreSQL is the one upstream recommends, and it's the only engine the next major version will keep supporting, so this guide uses it.

Weighing it against the other common pick? Wiki.js vs BookStack covers the difference: Wiki.js is free-form paths and Markdown, BookStack is a fixed shelves-books-pages structure. The BookStack guide covers that install.

Server sizing

Upstream's requirements are specific: at least 1 GB of RAM on Linux, and one CPU core works, but two or more are recommended so the background workers (rendering, search indexing) have room. The Wiki.js process usually sits around 70 MB and spikes during rendering and indexing. On our install-verification run (GCP e2-standard-2, Ubuntu 26.04) Wiki.js plus PostgreSQL idled at about 94 MB of RAM and 1.4 GB of disk.

  • 1 GB RAM / 1 vCPU — the floor for a small team wiki.
  • 2 GB RAM / 2 vCPU — the comfortable choice, and what upstream's CPU advice points to.

Upstream suggests at least 1 GB of storage for Wiki.js itself; text barely grows, uploads do. 20 GB of disk is a sensible start.

Prepare the server

This guide assumes Docker Engine and the Compose plugin are installed, along with a non-root user and a ufw firewall. If not, follow Docker & Compose on Ubuntu first.

Only SSH, 80 and 443 should be reachable:

sudo ufw status verbose
Where to host itaffiliate disclosure
Hetzner Cloudrun it on
2 vCPU · 4 GB RAM · 80 GB SSD · $23.59/mo
Get Hetzner Cloud (opens in new tab)
Kamaterafree trial
1 vCPU · 1 GB RAM · 20 GB SSD · $4.00/mo
Start free on Kamatera → (opens in new tab)
DigitalOceanalso works on
1 vCPU · 1 GB RAM · 25 GB SSD · $6.00/mo
Deploy on DigitalOcean → (opens in new tab)

Paid link — we earn a commission if you shop through it.

Install Wiki.js (Docker Compose)

Create the project directory:

mkdir -p ~/wikijs && cd ~/wikijs

Generate the database password once into a .env file. Compose reads it automatically, and the guard means re-running this step never replaces the password of a database that already exists:

[ -f .env ] || echo "DB_PASS=$(openssl rand -hex 16)" > .env
chmod 600 .env

The compose file follows the example in the Wiki.js Docker docs — the ghcr.io/requarks/wiki:2 image (upstream advises the major-version tag over latest) and postgres:15-alpine — with two changes: the password comes from .env, and the port is bound to loopback so only the reverse proxy can reach it:

cat > docker-compose.yml <<'YAML'
services:
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: wiki
      POSTGRES_PASSWORD: ${DB_PASS}
      POSTGRES_USER: wikijs
    restart: unless-stopped
    volumes:
      - db-data:/var/lib/postgresql/data

  wiki:
    image: ghcr.io/requarks/wiki:2
    depends_on: [db]
    init: true
    environment:
      DB_TYPE: postgres
      DB_HOST: db
      DB_PORT: 5432
      DB_USER: wikijs
      DB_PASS: ${DB_PASS}
      DB_NAME: wiki
    restart: unless-stopped
    ports:
      # Loopback only: Caddy is the only way in from outside.
      - "127.0.0.1:3000:3000"

volumes:
  db-data:
YAML

Start it and wait until Wiki.js answers:

docker compose up -d
for i in $(seq 1 60); do
  code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/)
  [ "$code" = "200" ] && break
  sleep 5
done
echo "Wiki.js answered HTTP $code"
docker compose ps

HTTP 200 means the setup page is being served. Wiki.js doesn't store content in the container: pages, users and settings live in PostgreSQL, and uploads are stored in the database too, which keeps backups to one dump.

HTTPS + domain

Wiki.js needs its own hostname — upstream is explicit that it can't be mapped to a subfolder. Point an A record for wiki.example.com at the server, wait for it to resolve, and put TLS in front with Automatic HTTPS with Caddy:

wiki.example.com {
    reverse_proxy 127.0.0.1:3000
}

If you run Caddy as a container, proxy to wiki:3000 on a shared network instead and drop the host port publish. Wiki.js can also request Let's Encrypt certificates itself (LETSENCRYPT_DOMAIN), but that means publishing its ports directly; letting Caddy handle TLS keeps renewals out of the application.

Run the setup wizard — immediately

The first visit to https://wiki.example.com shows a setup screen that asks for the administrator email, password and the site URL. Whoever submits it first owns the wiki, so complete it as soon as the domain resolves, before anyone else finds the page. Enter the https:// address as the site URL; it's used to build links and can be changed later under Administration → General.

Once you're in:

  • Administration → Users: create accounts for your team rather than sharing the admin login.
  • Administration → Groups: the built-in Guests group decides what logged-out visitors can see. For a private wiki, remove its read permissions.
  • Administration → Authentication: turn off self-registration on the local strategy unless you mean to allow it, or connect your LDAP, SAML or OIDC provider. Enable two-factor authentication for administrators.
  • Administration → Mail: SMTP is needed for invitations and password resets.

Backups

Everything that matters is in PostgreSQL. Dump it with the tools inside the database container:

cd ~/wikijs
docker compose exec -T db pg_dump -U wikijs wiki > wikijs-$(date +%F).sql
test -s wikijs-$(date +%F).sql && ls -lh wikijs-*.sql

Keep a copy of .env and docker-compose.yml with it, and copy all of it off the server. To restore onto a fresh install, start only the database (docker compose up -d db), feed the dump back with docker compose exec -T db psql -U wikijs wiki < wikijs-DATE.sql, then start the wiki service.

Wiki.js also has storage modules (under Administration → Storage) that can sync your pages to Git, S3 or a local folder as Markdown files. That's a useful second copy — pages you can read without Wiki.js — but it isn't a full backup of users and settings, so keep the database dump.

Upgrades

The :2 tag follows the latest 2.x release. To move to it:

cd ~/wikijs
docker compose pull
docker compose up -d

Wiki.js runs its database migrations on start. Take a dump first. Upstream has said the next major version will drop MySQL, MariaDB, MS SQL and SQLite, and an export/import tool is planned for moving between major versions — another reason to start on PostgreSQL.

Troubleshooting

The container restarts in a loop. Read docker compose logs wiki. A database connection error on the first boot usually means PostgreSQL was still initializing; it recovers on its own. A persistent authentication error means DB_PASS changed after the database was created — the password is set only when the data volume is first initialized.

Links and redirects point to the wrong host. The site URL from the setup wizard is wrong. Fix it under Administration → General.

Search returns nothing useful. The default basic search engine is limited. With PostgreSQL you can switch to the PostgreSQL search module under Administration → Search; the postgres image already includes the pg_trgm extension it needs.

Pages are slow right after a big import. Rendering and indexing run in the background and can spike memory; on a 1 GB box, give it a few minutes or add RAM.

Verification + next steps

You're done when https://wiki.example.com loads with a valid certificate, the setup wizard is gone and you can sign in as the administrator, a logged-out private window sees only what the Guests group allows, and a database dump sits somewhere off the server.

Next: connect your identity provider, turn on a Git storage module for a readable copy of every page, and schedule the pg_dump with cron. If you want real-time co-editing instead, see the Docmost guide. For host choices, see Best VPS for Self-Hosting.

Next steps

How to self-host Wiki.js →More self-hosted wiki & docs tools →Automatic HTTPS with Caddy →Run Claude Code with Ollama on Your Own VPS →Deploy Coolify on a VPS →How to Deploy Actual Budget on a VPS →How to Deploy AnythingLLM on a VPS →How to Deploy Appwrite on a VPS →How to Deploy Audiobookshelf on a VPS →How to Deploy Authelia on a VPS →How to Deploy authentik on a VPS →How to Deploy Baserow on a VPS →How to Deploy Beszel on a VPS →How to Deploy Bitwarden on a VPS →How to Deploy BookStack on a VPS →How to Deploy CapRover on a VPS →How to Deploy Checkmate on a VPS →How to Deploy Directus on a VPS →How to Deploy docker-mailserver on a VPS →How to Deploy Docmost on a VPS →How to Deploy Dokku on a VPS →How to Deploy Dokploy on a VPS →How to Deploy Firefly III on a VPS →How to Deploy Forgejo on a VPS →How to Deploy Gatus on a VPS →How to Deploy Ghostfolio on a VPS →How to Deploy Gitea on a VPS →How to Deploy GitLab on a VPS →How to Deploy GlitchTip on a VPS →How to Deploy Grafana on a VPS →How to Deploy Graylog on a VPS →How to Deploy Headscale on a VPS →How to Deploy Healthchecks on a VPS →How to Deploy Home Assistant on a VPS →How to Deploy Immich on a VPS →How to Deploy Jan on a VPS →How to Deploy Jellyfin on a VPS →How to Deploy Karakeep on a VPS →How to Deploy Keycloak on a VPS →How to Deploy Leantime on a VPS →How to Deploy LibreChat on a VPS →How to Deploy Linkwarden on a VPS →How to Deploy LocalAI on a VPS →How to Deploy Mailcow on a VPS →How to Deploy Mailu on a VPS →How to Deploy Matomo on a VPS →How to Deploy Mattermost on a VPS →How to Deploy Meilisearch on a VPS →How to Deploy Memos on a VPS →How to Deploy n8n on a VPS →How to Deploy Navidrome on a VPS →How to Deploy NetBird on a VPS →How to Deploy Netdata on a VPS →How to Deploy Nextcloud on a VPS →How to Deploy Next.js to a VPS →How to Deploy Nginx Proxy Manager on a VPS →How to Deploy NocoDB on a VPS →How to Deploy ntfy on a VPS →How to Deploy Ollama on a VPS →How to Deploy Open WebUI on a VPS →How to Deploy OpenHands on a VPS →How to Deploy OpenObserve on a VPS →How to Deploy OpenProject on a VPS →How to Deploy Outline on a VPS →How to Deploy Pangolin on a VPS →How to Deploy Paperless-ngx on a VPS →How to Deploy Passbolt on a VPS →How to Deploy Plane on a VPS →How to Deploy Plausible Analytics on a VPS →How to Deploy Pocket ID on a VPS →How to Deploy PocketBase on a VPS →How to Deploy Prometheus on a VPS →How to Deploy Psono on a VPS →How to Deploy Radarr on a VPS →How to Deploy Rocket.Chat on a VPS →How to Deploy SigNoz on a VPS →How to Deploy Sonarr on a VPS →How to Deploy Stalwart on a VPS →How to Deploy Stirling-PDF on a VPS →How to Deploy Supabase on a VPS →How to Deploy Synapse on a VPS →How to Deploy Taiga on a VPS →How to Deploy TeamPass on a VPS →How to Deploy Tinyauth on a VPS →How to Deploy Traefik on a VPS →How to Deploy Trilium on a VPS →How to Deploy Twenty CRM on a VPS →How to Deploy Umami on a VPS →How to Deploy Uptime Kuma on a VPS →How to Deploy Vaultwarden on a VPS →How to Deploy Vikunja on a VPS →How to Deploy wg-easy on a VPS →How to Deploy Zabbix on a VPS →How to Deploy Zitadel on a VPS →How to Deploy Zulip on a VPS →Docker & Compose on Ubuntu 26.04 →Building AI Workflows with n8n →Install Open WebUI with Ollama →Adding AI-Powered Insights to Plausible Analytics →Building AI-Powered Apps with Supabase and pgvector →

We use analytics cookies (Google Analytics, PostHog) to see which guides are useful. No ad networks, no cross-site tracking. See our privacy policy.