GuidesBusiness and monitoringTeam wiki with Outline

Run an Outline team wiki with rootless Podman

Outline on Debian 13, the fast team wiki with collections, live co-editing and full-text search, in rootless Podman with PostgreSQL and Valkey under a user of its own behind Caddy, with sign-in by email link and passkeys.

Tested on Outline 1.11.0 on Debian 13 (trixie) on a Melonslab server Updated October 14, 2026

Recommended server for this guide

SSD RAID 1 · ECC DDR4 · 10 Gbit

VC-P Alloy · 2 vCPU · 8 GB Memory · 60 GB Storage

Month to month, no lock-in 7-day money-back guarantee

€8.99/mo

Deploy now
On this page

What you will set up

Outline is a wiki and knowledge base for a team: routines, onboarding, meeting notes, how-tos. Documents live in collections, each with its own access, and can be nested inside each other. Several people can edit the same document at once and see each other's cursors. The editor works like a modern notes app, with Markdown shortcuts, tables, code blocks and images, and every change is kept in the document's history.

Outline is developed in the open on GitHub by General Outline, Inc., a company in the United States, which also sells it as a hosted service. The code is under the Business Source License 1.1: you may run it for your own organisation, but not sell it to others as a document service. Each release becomes open source under the Apache 2.0 licence four years after it comes out. The edition you run yourself for free leaves out some features of Outline's paid plans: sign-in with SAML, guest users, the audit log, import from Confluence and PDF export. Out of the box, the server reports the number of users, workspaces, collections and documents to Outline's update service once a day; step 3 switches that off.

Outline has no passwords. People sign in through a sign-in provider: Google, Microsoft, Slack, an OpenID Connect server such as authentik, or a link sent by email. This guide uses the email link, together with passkeys. For a small company it is the simplest choice: it needs no extra service to run and keep updated, only the email account you already have, and each person signs in with their work address. Once signed in, each person adds a passkey, so day-to-day sign-in does not wait for an email. If you already run authentik for your other apps, connecting Outline to it is the better choice, since you then turn off a leaver's access in one place. If authentik runs on this same server, Outline reaches it only with one of the fixes in step 8 of the Podman guide.

Here Outline runs as a pod under a user of its own called outline, with PostgreSQL for its data and Valkey for its queues, behind Caddy from the Podman guide.

Every step below was run on a fresh Melonslab VC-P Alloy (2 vCPU, 8 GB) with Debian 13:

  • Outline 1.11.0 started with PostgreSQL 18 and Valkey 9. The workspace and its admin were created from the server before Caddy was set up, and a second attempt to create a workspace was refused.
  • The admin and an invited user signed in with the email link, and the invite arrived by email. The admin then signed in with a passkey with email switched off.
  • A private collection and a shared one were created. The invited user saw only the shared one, and could not find the private documents by search.
  • A document got text, an uploaded image of 5.7 MB and a second version in its history. Search found words in the text. The image could not be opened without signing in.
  • A sign-in with an address that had not been invited sent no email. A suspended user was signed out at once and could not get a new sign-in link.
  • The interface was shown in Swedish, for one user and as the default for new users.
  • Sign-in requests were logged with the visitor's real address, over IPv4 and IPv6, and a forged X-Forwarded-For header was ignored. A capture of the server's traffic showed no reports to Outline's update service.
  • An update from Outline 1.10.1 to 1.11.0, by changing the tag, kept every document. The wiki was restored from a backup into empty volumes, and everything came back by itself after a reboot, including an edit made just before it.

The pod used about 300 MB of memory, most of it Outline itself.

Before you start

You need:

  • a server set up as in the Podman guide, with Caddy running;
  • an A record and an AAAA record for wiki.example.com pointing at your server;
  • an email account that can send through your email provider's SMTP server, such as wiki@example.com, with its server name and password. Without it, nobody can sign in.

The examples use wiki.example.com for the wiki, smtp.example.com for your provider's SMTP server, wiki@example.com for the account that sends the email, and anna@example.com for you. Replace them throughout.

1. Create the user

As root:

useradd -m -s /bin/bash outline
loginctl enable-linger outline
machinectl shell outline@

Everything up to step 5 runs as outline.

2. Create the secrets

openssl rand -hex 32 | tr -d '\n' | podman secret create outline-secret-key -
openssl rand -hex 32 | tr -d '\n' | podman secret create outline-utils-secret -
openssl rand -hex 24 | tr -d '\n' | podman secret create outline-db-password -
printf %s 'the-smtp-password' | podman secret create outline-smtp-password -

The first is Outline's secret key, which signs sign-in sessions and encrypts the secrets of any integrations you add. The second signs Outline's internal maintenance requests. The third is the database password, and the last is the password of your email account, in place of the-smtp-password. All four are stored by Podman, not in the files below.

3. Define the pod

mkdir -p ~/.config/containers/systemd
cd ~/.config/containers/systemd

Create outline.pod:

[Pod]
PodName=outline
# Only Caddy, on this server, can reach Outline: the port is not open to the internet.
PublishPort=127.0.0.1:8115:3000

[Install]
WantedBy=default.target

Create outline-db.container:

[Container]
ContainerName=outline-db
Image=docker.io/library/postgres:18-alpine
Pod=outline.pod
Volume=outline-db:/var/lib/postgresql
Environment=POSTGRES_USER=outline POSTGRES_DB=outline
Secret=outline-db-password,type=env,target=POSTGRES_PASSWORD
HealthCmd=pg_isready -U outline
HealthInterval=10s
Notify=healthy
AutoUpdate=registry

[Service]
Restart=always

Create outline-valkey.container:

[Container]
ContainerName=outline-valkey
Image=docker.io/valkey/valkey:9-alpine
Pod=outline.pod
Volume=outline-valkey:/data
AutoUpdate=registry

[Service]
Restart=always

And outline-app.container:

[Unit]
Requires=outline-db.service outline-valkey.service
After=outline-db.service outline-valkey.service

[Container]
ContainerName=outline-app
Image=docker.io/outlinewiki/outline:1.11
Pod=outline.pod
Volume=outline-data:/var/lib/outline/data
Environment=URL=https://wiki.example.com PORT=3000
Environment=DATABASE_HOST=127.0.0.1 DATABASE_NAME=outline DATABASE_USER=outline PGSSLMODE=disable
Environment=REDIS_URL=redis://127.0.0.1:6379
Environment=FILE_STORAGE=local FILE_STORAGE_UPLOAD_MAX_SIZE=26214400
Environment=TELEMETRY=false
Environment=SMTP_HOST=smtp.example.com SMTP_PORT=587 SMTP_SECURE=false
Environment=SMTP_USERNAME=wiki@example.com SMTP_FROM_EMAIL=wiki@example.com
Secret=outline-secret-key,type=env,target=SECRET_KEY
Secret=outline-utils-secret,type=env,target=UTILS_SECRET
Secret=outline-db-password,type=env,target=DATABASE_PASSWORD
Secret=outline-smtp-password,type=env,target=SMTP_PASSWORD
AutoUpdate=registry

[Service]
Restart=always

What the settings do:

  • URL is the address Outline puts in every link and email. It must be the public https:// address.
  • The DATABASE_ lines point Outline at PostgreSQL in the same pod, and PGSSLMODE=disable lets it connect without TLS, which stays inside the pod.
  • Valkey, a fork of Redis, holds Outline's job queues. Its volume keeps jobs that are waiting, such as saving a new version of a document, across a restart. It needs no backup.
  • FILE_STORAGE=local keeps uploaded images and files in the outline-data volume instead of S3 storage. Outline's own limit for an upload is 1 MB; 26214400 raises it to 25 MB.
  • TELEMETRY=false stops the daily report to Outline's update service.
  • The SMTP_ lines are for your email provider, step 7 has the details.
  • The tag 1.11 follows the patch releases of Outline 1.11, which AutoUpdate=registry installs by itself. Step 12 covers moving to the next version.

Start it:

systemctl --user daemon-reload
systemctl --user start outline-pod
systemctl --user enable --now podman-auto-update.timer

The first start downloads images that take about 1.5 GB on disk, and Outline takes a minute or two to set up its database. It is ready when this prints 301, a redirect to HTTPS:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8115/

4. Create the workspace

Until a workspace exists, Outline lets the first visitor create it, with themselves as admin. Do that from the server, before the wiki is online, with your workspace's name, your name and your email address:

curl -s -X POST http://127.0.0.1:8115/api/installation.create \
  -H 'X-Forwarded-Proto: https' -H 'Content-Type: application/json' \
  -d '{"teamName": "Example", "userName": "Anna Svensson", "userEmail": "anna@example.com"}'

It prints Redirecting to https://wiki.example.com/home. Run it again and it says Installation already has existing teams: from now on, nobody can create another one.

5. Put Caddy in front

Go back to root with exit, switch to machinectl shell caddy@, and add this block at the end of ~/Caddyfile:

wiki.example.com {
    reverse_proxy 127.0.0.1:8115
}

Restart Caddy with systemctl --user restart caddy, and open https://wiki.example.com. The page says Log in to Example. Choose Continue with Email, enter your address and choose Sign In. An email with the subject "Magic Sign-in Link" arrives within a minute, and its link signs you in.

Caddy passes on each visitor's address in the X-Forwarded-For header, and Outline trusts it. That is safe here because only Caddy can reach Outline's port, and Caddy replaces any such header a visitor sends.

6. Add a passkey

A passkey lets you sign in with your phone, your computer's fingerprint reader or a security key, without waiting for an email. Open the menu under your name at the bottom left, and choose Preferences. That opens Outline's settings, with your own on the left under Account and, for admins, the workspace's under Workspace. Choose Passkeys, then Add Passkey…. Your browser asks where to save it. From then on, the login page has Continue with Passkey as well.

Ask everyone to add one after their first sign-in. A passkey works on the device or in the password manager where it was saved; on a new device, people sign in by email again and add another.

7. Email

Outline sends email for sign-in links, invites, notifications about documents people follow, links to finished exports, and a note to admins when someone joins. Without email, the login page has no Continue with Email: people who have added a passkey can still sign in, but nobody else can, and no new user can sign in for the first time.

The SMTP_ lines in step 3 send through your email provider on port 587 with STARTTLS, which SMTP_SECURE=false asks for: Outline connects without TLS and upgrades the connection as soon as the server offers it. For port 465, which uses TLS from the start, use SMTP_PORT=465 SMTP_SECURE=true. SMTP_FROM_EMAIL is the sender people see, and most providers require it to be the same as the account.

To change a setting later, edit outline-app.container as outline and restart:

systemctl --user daemon-reload
systemctl --user restart outline-app

To change the password, remove the secret with podman secret rm outline-smtp-password, create it again as in step 2, and restart the same way. If a sign-in email does not arrive, see Troubleshooting. We tested the emails with a test mail server on the same machine, not through a real provider.

8. Invite your team

Choose Invite people… at the bottom left, enter each person's email address and name, choose their role, and Send Invites:

  • Editor can create, edit and delete documents.
  • Viewer can read and comment.
  • Admin can also change every workspace setting.

Each person gets an email, "Anna Svensson invited you to join Example's workspace", with a link to the wiki, where they sign in with Continue with Email. Only invited addresses can sign in: for any other address, Outline sends no email. Allowed domains under Authentication in the settings does not change that, as it applies only to sign-in providers such as Google or OpenID Connect.

When someone leaves, open Users in the settings, choose User options (the three dots) next to them, then Suspend user… and Confirm. That signs them out at once and stops them getting new sign-in links, even if they still have access to the mailbox.

Check two settings under Security in the settings before you invite anyone:

  • Public document sharing is on, so any member can publish a document on the internet with a link that needs no sign-in. Switch it off if the wiki is for internal use only.
  • Allow users to send invites is on, so editors can invite people too.

9. Collections and documents

Documents live in collections, such as Handbook or Servers. To create one, choose New collection in the sidebar, give it a name, and set Permission:

  • No access makes it private: only you, and the people and groups you add later with Share on the collection, can see it.
  • View only or Can edit opens it to everyone in the workspace.

Then choose New doc at the top right. The first line is the title. Type / on an empty line for the list of blocks: headings, lists, tables, code blocks, and Image, which uploads a picture from your computer. You can also paste or drag images in. Markdown shortcuts such as # and ** work as you type. A document can hold other documents, which you create with New document in its menu, the three dots at the top right.

Changes save as you type, and others who have the document open see them at once. History in the same menu lists earlier versions, with what changed. A new version is saved when everyone has closed the document, or five minutes after the last change.

The search box at the top searches titles and text in every collection you can see. A document's text becomes searchable at the same moment a version is saved, so a word you have just typed can take up to five minutes to show up. Export in the menu gives you the document as Markdown or HTML. PDF is not offered: in our test, Outline answered PDF export is not available in the community edition.

Uploaded images and files need a sign-in: a visitor who has an image's address gets an error. Anyone in the workspace who has the address of an image can open it, even if it is in a private collection, but the addresses are long and random.

10. Use Outline in Swedish

Outline comes translated into Swedish. Each user picks Svenska (Swedish) under Language in Preferences.

To make Swedish the language of new users, add this line to outline-app.container, as outline, and restart as in step 7:

Environment=DEFAULT_LANGUAGE=sv_SE

People who have already signed in keep the language they have. The login page follows the language of the visitor's browser.

11. Back up

As outline:

umask 077
mkdir -p ~/backup
podman exec outline-db pg_dump -U outline -d outline > ~/backup/outline-db.sql
podman volume export outline-data > ~/backup/outline-data.tar
for s in outline-secret-key outline-utils-secret; do podman secret inspect --showsecret --format '{{.SecretData}}' $s > ~/backup/$s.txt; done

That saves the database, with all documents, history, users and settings; the uploaded images and files; and the two keys from step 2. The dump runs while Outline keeps working. umask 077 makes new files readable by outline only; podman volume export --output would ignore it, which is why the line uses >. Copy ~/backup to another machine, for example with restic, and store it safely: it holds all your content and the keys.

Export data… under Export in the settings also exports every collection as Markdown or HTML in a ZIP file, and emails you a link when it is ready. That is a good copy to read without Outline, but it is not a full backup: users, permissions and history are not in it.

To restore into an empty pod, as outline, with the backup in ~/backup:

systemctl --user stop outline-pod
podman volume rm outline-db outline-data
podman volume create outline-data
podman volume import outline-data ~/backup/outline-data.tar
systemctl --user start outline-db
podman exec -i outline-db psql -q -U outline -d outline < ~/backup/outline-db.sql
systemctl --user start outline-pod

Starting only the database first loads the backup before Outline sets up an empty one. On a new server, create the two keys from the backup instead of new ones in step 2:

for s in outline-secret-key outline-utils-secret; do tr -d '\n' < ~/backup/$s.txt | podman secret create $s -; done

12. Update

podman auto-update checks once a day for new images of Outline, PostgreSQL and Valkey, and restarts the pod when one has changed. Outline updates its database when it starts. To update now:

podman auto-update

Outline publishes a new version, such as 1.12, every month or two. Read its release notes on GitHub, make a backup, then change the tag in outline-app.container, such as 1.11 to 1.12, and restart:

systemctl --user daemon-reload
systemctl --user restart outline-app

Outline updates its database as it starts. Admins see the installed version, and whether a newer one exists, under Installation in the settings. To show that, Outline looks up the latest version on Docker Hub when the page opens.

Troubleshooting

The login page has no Continue with Email. The SMTP_ lines are missing from outline-app.container, and Outline only offers email sign-in when it can send email. Add them as in step 3, and restart.

The sign-in email never arrives. As outline, run journalctl --user -u outline-app | grep -i mail. A line with "Error sending email" has the email server's answer, or the reason it could not be reached. If the answer is about the login, check the account and the password secret; if the connection times out, your provider may want the other port, 587 or 465.

"Rate limit exceeded" after asking for a sign-in email. Outline accepts ten requests for a sign-in email an hour from each address. The limit is set in Outline's code, and RATE_LIMITER_REQUESTS does not change it. Wait up to an hour and try again. Everyone behind one office address shares the ten.

The page stays blank, or loads only half, after many reloads. Outline allows 1000 requests a minute from one address, and a first visit without a cache loads a few hundred files. Wait a minute. If a whole office shares one address and hits the limit, raise it with Environment=RATE_LIMITER_REQUESTS=3000.

An upload fails. The file may be bigger than FILE_STORAGE_UPLOAD_MAX_SIZE, in bytes. Raise it in outline-app.container, and restart.

Run it on your own server

SSD RAID 1 · ECC DDR4 · 10 Gbit

VC-P Alloy

€8.99/mo

vCPU
2
Memory
8 GB
Storage
60 GB
Transfer
10 TB
Performance
SSD · RAID 1
  • Full root access
  • Native /64 IPv6
  • RAID-protected storage
  • Malmö, Sweden
  • Month to month, no lock-in
  • 7-day money-back guarantee
All guides