--- title: "How to Install Outline Wiki with Docker on Ubuntu 24.04" description: "Deploy the Outline team wiki on Ubuntu 24.04 with Docker Compose, PostgreSQL and Redis, sign in through OpenID Connect and publish it over HTTPS with Nginx." category: "Web Applications Hosting" language: en source: https://cubepath.com/docs/web-applications-hosting/outline-wiki-installation-with-docker updated: 2026-09-25 --- # How to Install Outline Wiki with Docker on Ubuntu 24.04 Outline is an open-source knowledge base for teams, with a fast Markdown editor, real-time collaboration and full-text search. In this tutorial you will run Outline, PostgreSQL and Redis with Docker Compose on Ubuntu 24.04, store uploads on the local disk, sign in through an OpenID Connect (OIDC) provider, and publish the wiki over HTTPS behind Nginx. You will finish with a scheduled database backup. ## Prerequisites To follow this guide you need: - A server running Ubuntu 24.04 LTS with at least 2 GB of RAM (4 GB recommended) and 20 GB of free disk, for example a CubePath VPS. - A non-root user with `sudo` privileges. - A domain name, referred to as `your_domain` (for example `wiki.example.com`), with a DNS A record pointing to `your_server_ip`. - An OpenID Connect provider where you can register an application, such as Authentik, Keycloak, Authelia, Zitadel or Google Workspace. Outline has no built-in username and password login, so the first user must come from an identity provider. ## Step 1 - Installing Docker Engine and Docker Compose Outline is distributed as a container image, so install Docker Engine and the Compose plugin from Docker's official repository. First add the repository key: ```bash sudo apt update sudo apt install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc ``` Add the repository and install the packages: ```bash echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin ``` Check that both components respond: ```bash sudo docker --version sudo docker compose version ``` ```output Docker version 28.x.x, build xxxxxxx Docker Compose version v2.x.x ``` This guide runs Docker with `sudo`. Adding your user to the `docker` group also works, but that group is equivalent to root access. ## Step 2 - Registering Outline with your OIDC provider In your identity provider, create a new OAuth2/OpenID Connect application (a "confidential" client) with these settings: - **Redirect URI**: `https://your_domain/auth/oidc.callback` - **Scopes**: `openid`, `profile`, `email` Note the **client ID**, the **client secret**, and the three endpoint URLs the provider shows: authorization, token and userinfo. Most providers list them on the application page or in their discovery document at `https://your_idp/.well-known/openid-configuration`. ## Step 3 - Creating the Outline configuration Create a directory for the deployment and move into it: ```bash sudo mkdir -p /opt/outline cd /opt/outline ``` Outline needs two random secrets and PostgreSQL needs a password. Generate them now and keep the output at hand: ```bash openssl rand -hex 32 openssl rand -hex 32 openssl rand -hex 16 ``` The first value is `SECRET_KEY`, the second is `UTILS_SECRET`, and the third is the database password, referred to as `your_db_password`. A hex password avoids characters that would need escaping inside the database URL. Create the environment file that the Outline container reads: ```bash sudo nano /opt/outline/docker.env ``` Paste the following, replacing every placeholder: ```ini NODE_ENV=production URL=https://your_domain PORT=3000 FORCE_HTTPS=true SECRET_KEY=your_secret_key UTILS_SECRET=your_utils_secret DATABASE_URL=postgres://outline:your_db_password@postgres:5432/outline PGSSLMODE=disable REDIS_URL=redis://redis:6379 FILE_STORAGE=local FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data FILE_STORAGE_UPLOAD_MAX_SIZE=262144000 OIDC_CLIENT_ID=your_client_id OIDC_CLIENT_SECRET=your_client_secret OIDC_AUTH_URI=https://your_idp/authorize OIDC_TOKEN_URI=https://your_idp/token OIDC_USERINFO_URI=https://your_idp/userinfo OIDC_USERNAME_CLAIM=preferred_username OIDC_DISPLAY_NAME=Company SSO OIDC_SCOPES=openid profile email ``` `URL` must match the public address exactly, including `https://`, or sign-in redirects will fail. `FILE_STORAGE=local` keeps uploads in a Docker volume so you don't need an S3 bucket. `OIDC_DISPLAY_NAME` is the label shown on the login button. The file contains secrets, so restrict it to root: ```bash sudo chmod 600 /opt/outline/docker.env ``` ## Step 4 - Writing the Docker Compose file Create the Compose file: ```bash sudo nano /opt/outline/compose.yml ``` Add the three services. Use the same `your_db_password` value as in `DATABASE_URL`: ```yaml services: outline: image: docker.getoutline.com/outlinewiki/outline:latest restart: unless-stopped env_file: ./docker.env ports: - "127.0.0.1:3000:3000" volumes: - storage-data:/var/lib/outline/data depends_on: postgres: condition: service_healthy redis: condition: service_started redis: image: redis:7 restart: unless-stopped postgres: image: postgres:16 restart: unless-stopped environment: POSTGRES_USER: outline POSTGRES_PASSWORD: your_db_password POSTGRES_DB: outline volumes: - database-data:/var/lib/postgresql/data healthcheck: test: ["CMD", "pg_isready", "-U", "outline", "-d", "outline"] interval: 10s timeout: 5s retries: 5 volumes: storage-data: database-data: ``` Only Outline publishes a port, and only on `127.0.0.1`. Ports published by Docker bypass UFW rules, so binding to localhost is what keeps the application reachable only through Nginx. PostgreSQL and Redis stay on the internal Compose network. Protect the file, since it also contains the password: ```bash sudo chmod 600 /opt/outline/compose.yml ``` ## Step 5 - Starting the stack Pull the images and start the containers in the background: ```bash cd /opt/outline sudo docker compose up -d ``` On first start Outline runs its database migrations, which takes up to a minute. Check the state of the services: ```bash sudo docker compose ps ``` All three services should show `Up`, and `postgres` should report `(healthy)`. Follow the Outline log to confirm that migrations finished without errors: ```bash sudo docker compose logs -f outline ``` Press `Ctrl+C` to stop following the log. Then check that Outline answers locally: ```bash curl -I http://127.0.0.1:3000 ``` Any HTTP response confirms the application is listening. Because `FORCE_HTTPS=true`, a redirect to `https://` is expected at this stage. ## Step 6 - Configuring Nginx as a reverse proxy Install Nginx and allow SSH, HTTP and HTTPS through the firewall: ```bash sudo apt install nginx sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' sudo ufw enable ``` Create a server block for the wiki: ```bash sudo nano /etc/nginx/sites-available/outline ``` Outline uses WebSockets for real-time collaboration, so the proxy must pass the `Upgrade` headers: ```nginx map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80; listen [::]:80; server_name your_domain; client_max_body_size 250M; location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $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; } } ``` Enable the site, test the syntax and reload Nginx: ```bash sudo ln -s /etc/nginx/sites-available/outline /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx ``` ```output nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful ``` ## Step 7 - Enabling HTTPS with Let's Encrypt Install Certbot with its Nginx plugin and request a certificate. Certbot adds the TLS directives and an HTTP to HTTPS redirect to the server block for you: ```bash sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d your_domain ``` The Ubuntu package installs a systemd timer that renews certificates automatically. Confirm renewal works with a dry run: ```bash sudo certbot renew --dry-run ``` ## Step 8 - Signing in and creating the workspace Open `https://your_domain` in your browser. You will see a button with the name you set in `OIDC_DISPLAY_NAME`. Click it, authenticate with your provider, and Outline creates the workspace with you as its first administrator. Everyone who can authenticate against your OIDC application can join the workspace, so restrict access on the provider side (group or policy bindings), or adjust the allowed domains under **Settings > Security** in Outline. > Note: Invitations and notification emails need SMTP. Add `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_FROM_EMAIL` and `SMTP_SECURE` to `docker.env`, then run `sudo docker compose up -d` to recreate the container. ## Step 9 - Backing up the database and uploads Outline keeps documents in PostgreSQL and attachments in the `storage-data` volume. Create a backup script: ```bash sudo nano /usr/local/bin/outline-backup ``` ```bash #!/usr/bin/env bash set -euo pipefail backup_dir="/var/backups/outline" stamp="$(date +%Y%m%d-%H%M%S)" mkdir -p "$backup_dir" cd /opt/outline docker compose exec -T postgres pg_dump -U outline -d outline \ | gzip > "$backup_dir/outline-db-$stamp.sql.gz" docker run --rm -v outline_storage-data:/data:ro -v "$backup_dir":/backup \ alpine tar -czf "/backup/outline-files-$stamp.tar.gz" -C /data . find "$backup_dir" -type f -mtime +14 -delete ``` Compose prefixes volume names with the project name, which is the directory name (`outline`), so the uploads volume is `outline_storage-data`. Make the script executable and run it once: ```bash sudo chmod 750 /usr/local/bin/outline-backup sudo /usr/local/bin/outline-backup ls -lh /var/backups/outline ``` Schedule it every night at 02:30 with a cron file: ```bash echo '30 2 * * * root /usr/local/bin/outline-backup' | sudo tee /etc/cron.d/outline-backup ``` Copy the backup directory to another machine or object storage; a backup on the same disk does not protect against losing the server. ## Updating Outline Pull the new image and recreate the container. Migrations run automatically on start: ```bash cd /opt/outline sudo /usr/local/bin/outline-backup sudo docker compose pull sudo docker compose up -d ``` Read the release notes on GitHub before jumping several versions, and pin a specific tag instead of `latest` if you prefer controlled upgrades. ## Troubleshooting - **The OIDC login returns a redirect URI error**: the redirect URI registered in the provider must be exactly `https://your_domain/auth/oidc.callback`, and `URL` in `docker.env` must use the same host and `https://`. - **Outline restarts in a loop with a database error**: the password in `DATABASE_URL` does not match `POSTGRES_PASSWORD`. PostgreSQL only applies that variable when the volume is first created, so if you changed it later, run `sudo docker compose down -v` (this deletes all data) on a fresh install, or change the password inside PostgreSQL. - **Real-time editing does not sync or shows "connection lost"**: the Nginx server block is missing the `Upgrade` and `Connection` headers. - **Uploads fail**: check `client_max_body_size` in Nginx and `FILE_STORAGE_UPLOAD_MAX_SIZE` in `docker.env`, then inspect `sudo docker compose logs outline`. ## Conclusion Outline is now running on Ubuntu 24.04 with PostgreSQL, Redis and local file storage, served over HTTPS and protected by your identity provider, with nightly backups. As next steps, configure SMTP so users receive invitations and notifications, import existing Markdown or Confluence content from **Settings > Import**, and move uploads to S3-compatible storage if the wiki will hold many large attachments.