Install Outline with docker compose and Traefik

Recently N8N presented this list of interesting workflow automation software and one of them, Outline, picked my curiosity and I decided to try it out. Here's how I deployed it on my server with docker compose and Traefik as a proxy layer.
What is Outline?
On their website, https://www.getoutline.com/, outline presents itself as "Your team’s knowledge base". A tool to basically write any shared written document your organization may need for functioning correctly.
Why hosting it yourself?
If you're an individual who enjoys hosting this kind of software yourself or if you need to cut the cost of SaaS software, this tool seems like a great way to run it without committing to a paid subscription.
If you don't have a server already, Digital Ocean have a great offering with promotional credit.
Once you find that it became a fundamental tool for your business, you can cut on the management cost by picking a cloud plan hosted by outline directly.
How to install Outline?
To install outline, I opted for a docker compose installation, with secrets managed externally by doppler and pushed when running the docker compose file using doppler run --
.
Here's my docker compose file
version: "3"
x-defaults: &defaults
environment:
- DATABASE_URL=${DATABASE_URL:-"postgres://user:pass@postgres_outline:5432/outline"}
- DATABASE_URL_TEST=${DATABASE_URL_TEST:-"postgres://user:pass@postgres_outline:5432/outline"}
- DEFAULT_LANGUAGE=${DEFAULT_LANGUAGE:-"en_US"}
- ENABLE_UPDATES=${ENABLE_UPDATES:-true}
- FORCE_HTTPS=${FORCE_HTTPS:-true}
- LOG_LEVEL=${LOG_LEVEL:-info}
- MAXIMUM_IMPORT_SIZE=${MAXIMUM_IMPORT_SIZE:-5120000}
- NODE_ENV=${NODE_ENV:-production}
- PGSSLMODE=${PGSSLMODE:-disable}
- PORT=${PORT:-3000}
- PRODUCTION_SSL_DISABLED=${PRODUCTION_SSL_DISABLED:-true}
- RATE_LIMITER_DURATION_WINDOW=${RATE_LIMITER_DURATION_WINDOW:-60}
- RATE_LIMITER_ENABLED=${RATE_LIMITER_ENABLED:-true}
- RATE_LIMITER_REQUESTS=${RATE_LIMITER_REQUESTS:-1000}
- REDIS_URL=${REDIS_URL:-"redis://redis_outline:6379"}
- SECRET_KEY=${SECRET_KEY:-"secret_key"}
- SLACK_APP_ID=${SLACK_APP_ID:-"SLACK_APP_ID"}
- SLACK_CLIENT_ID=${SLACK_CLIENT_ID:-"SLACK_APP_ID"}
- SLACK_CLIENT_SECRET=${SLACK_CLIENT_SECRET:-"SLACK_CLIENT_SECRET"}
- SLACK_MESSAGE_ACTIONS=${SLACK_MESSAGE_ACTIONS:-"SLACK_MESSAGE_ACTIONS"}
- SLACK_VERIFICATION_TOKEN=${SLACK_VERIFICATION_TOKEN:-"SLACK_VERIFICATION_TOKEN"}
- SMTP_FROM_EMAIL=${SMTP_FROM_EMAIL:-"SMTP_FROM_EMAIL"}
- SMTP_HOST=${SMTP_HOST:-"SMTP_HOST"}
- SMTP_PASSWORD=${SMTP_PASSWORD:-"SMTP_HOST"}
- SMTP_PORT=${SMTP_PORT:-465}
- SMTP_REPLY_EMAIL=${SMTP_REPLY_EMAIL:-"SMTP_REPLY_EMAIL"}
- SMTP_SECURE=${SMTP_SECURE:-true}
- SMTP_USERNAME=${SMTP_USERNAME:-"SMTP_USERNAME"}
- URL=${URL:-"URL"}
- UTILS_SECRET=${UTILS_SECRET:-"UTILS_SECRET"}
- WEB_CONCURRENCY=${WEB_CONCURRENCY:-1}
- DB_TYPE=${DB_TYPE:-"postgres"}
- DB_HOST=${DB_HOST:-"postgres_outline"}
- DB_NAME=${DB_NAME:-"outline"}
- DB_USER=${DB_USER:-"user"}
- DB_PASS=${DB_PASS:-"pass"}
- DB_DUMP_FREQ=${DB_DUMP_FREQ:-720}
- DB_CLEANUP_TIME=${DB_CLEANUP_TIME:-"72000"}
- CHECKSUM=${CHECKSUM:-"SHA1"}
- COMPRESSION=${COMPRESSION:-"GZIP"}
- SPLIT_DB=${SPLIT_DB:-true}
- CONTAINER_ENABLE_MONITORING=${CONTAINER_ENABLE_MONITORING:-false}
- MINIO_ROOT_USER=${MINIO_ROOT_USER:-"minioadmin"}
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:-"minioadmin"}
services:
outline:
<<: *defaults
image: docker.getoutline.com/outlinewiki/outline:0.69.2
ports:
- "3000:3000"
depends_on:
- postgres
- redis
- storage
networks:
- traefik
- default
labels:
- traefik.enable=true
- traefik.http.routers.outline-${NUMBER:-1}.rule=Host(`outline.example.com`)
- traefik.http.routers.outline-${NUMBER:-1}.entrypoints=websecure
- traefik.http.routers.outline-${NUMBER:-1}.service=outline-${NUMBER:-1}
- traefik.http.routers.outline-${NUMBER:-1}.tls.certresolver=letsencrypt
- traefik.http.services.outline-${NUMBER:-1}.loadbalancer.server.port=3000
redis:
image: redis
ports:
- "6379:6379"
command: ["redis-server"]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 30s
retries: 3
container_name: redis_outline
postgres:
image: postgres
<<: *defaults
ports:
- "5432:5432"
volumes:
- ./data/database-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready"]
interval: 30s
timeout: 20s
retries: 3
container_name: postgres_outline
storage:
image: minio/minio
container_name: minio_outline
<<: *defaults
entrypoint: sh
command: -c 'minio server /data'
deploy:
restart_policy:
condition: on-failure
volumes:
- ./data/storage-data:/data
healthcheck:
test: ["CMD", "curl", "-f", "http://minio_outline:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
db_backup:
container_name: outline_db_backup
image: tiredofit/db-backup
depends_on:
- postgres
volumes:
- ../backups/outline_danielpetrica_com/outline_db/:/backup
<<: *defaults
restart: always
networks:
default:
driver: in
attachable: true
traefik:
external: true
name: traefik
docker-compose.yml
As you can see in the x-defaults
section I define all the environment variables which I then push into the different services. If you're not using doppler you can set the variables with in the same terminal before you start the dockers.
export variableName=value
Command use to configure VariableName environment variable so that the docker command can read it
Another option to load environment variables in the services is to use a .env file like how is done in the original documentation. Here's an example of how it must be https://github.com/outline/outline/blob/main/.env.sample. To load this file replace <<: *defaults
for env_file: ./docker.env
The docker file uses two networks, the traefik one for the public facing endpoint and an internal one just for this dockers.
Safety
To stay safe online, traefik creates a SSL certificate and exposes your site on the domain specified on the docker labels using https.
As a recovery option, I configured the project tiredofit/db-backup to periodically save the database.
With time, it would be an intelligent thing to also save this destination folder with all the backups to another location, but I'm leaving it for another day, as time in never enough.
Additional note
In the docker compose I configured a minio service but for lack of time I'm still not using it inside outline.
Thank you for reading so far.
In this article, we've explored how to run Outline on a docker compose plus traefik stack to make hosting it easy. Let me know if you have any questions in the comment section below. Also, please ask me if you want similar guides for other software
Comments ()