Outline es una wiki y base de conocimiento de código abierto para equipos, con edición colaborativa en tiempo real, búsqueda y un editor compatible con Markdown. En este tutorial desplegarás Outline en Ubuntu 24.04 con Docker Compose, PostgreSQL y Redis, lo publicarás detrás de Nginx con un certificado de Let's Encrypt y configurarás el inicio de sesión con un proveedor OpenID Connect (OIDC).

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 2 GB de RAM y 20 GB libres en disco.
  • Un usuario no root con privilegios sudo que pertenezca al grupo docker.
  • Docker Engine y el plugin Docker Compose instalados desde el repositorio oficial de Docker.
  • Un dominio o subdominio con un registro DNS A apuntando a la IP del servidor. En esta guía se usa your_domain.
  • Acceso a un proveedor de identidad compatible con OIDC (Authentik, Keycloak, Microsoft Entra ID, Google Workspace, etc.). Outline no tiene usuarios con contraseña propia: el primer acceso siempre se hace a través de un proveedor de autenticación.

Paso 1: Registrar Outline en tu proveedor OIDC

Antes de arrancar Outline necesitas un cliente OAuth en tu proveedor de identidad. Crea una aplicación de tipo "web" o "confidential" con esta URL de redirección (callback):

https://your_domain/auth/oidc.callback

Anota estos datos, que usarás en el paso 3:

  • ID de cliente (client ID) y secreto de cliente (client secret).
  • URL de autorización, URL de token y URL de userinfo. Los encontrarás en el documento de descubrimiento de tu proveedor, normalmente en https://tu_proveedor/.well-known/openid-configuration.

Los ámbitos que Outline solicita son openid, profile y email, así que el proveedor debe devolver al menos el correo electrónico del usuario.

Paso 2: Crear el archivo de Docker Compose

Crea un directorio para el proyecto. Docker Compose usa su nombre (outline) como prefijo de los volúmenes:

sudo mkdir -p /opt/outline
sudo chown "$USER":"$USER" /opt/outline
cd /opt/outline

Crea el archivo compose.yaml:

nano compose.yaml
services:
  outline:
    image: outlinewiki/outline:latest
    env_file: .env
    ports:
      - "127.0.0.1:3000:3000"
    volumes:
      - storage-data:/var/lib/outline/data
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: unless-stopped

  redis:
    image: redis:7
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  postgres:
    image: postgres:16
    environment:
      POSTGRES_USER: outline
      POSTGRES_DB: outline
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - database-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "outline", "-d", "outline"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

volumes:
  storage-data:
  database-data:

Algunos detalles de esta configuración:

  • Outline solo escucha en 127.0.0.1:3000, de modo que el único acceso desde Internet será a través de Nginx. PostgreSQL y Redis no publican ningún puerto.
  • depends_on con service_healthy evita que Outline arranque antes de que la base de datos acepte conexiones.
  • Los archivos subidos se guardan en el volumen storage-data y la base de datos en database-data.

Paso 3: Generar los secretos y la configuración

Outline se configura con variables de entorno. Genera la contraseña de PostgreSQL y las dos claves secretas con openssl, y escribe el archivo .env en un solo paso. Cambia your_domain antes de ejecutarlo:

DB_PASS="$(openssl rand -hex 24)"
cat > .env <<EOF
NODE_ENV=production
URL=https://your_domain
PORT=3000
FORCE_HTTPS=true

SECRET_KEY=$(openssl rand -hex 32)
UTILS_SECRET=$(openssl rand -hex 32)

POSTGRES_PASSWORD=${DB_PASS}
DATABASE_URL=postgres://outline:${DB_PASS}@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
EOF
chmod 600 .env

PGSSLMODE=disable es necesario porque el contenedor de PostgreSQL no usa TLS en la red interna de Docker. FILE_STORAGE_UPLOAD_MAX_SIZE limita las subidas a 250 MB.

Ahora añade los datos de tu proveedor OIDC al final del archivo:

nano .env
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=SSO
OIDC_SCOPES=openid profile email

Sustituye las URL por las que figuran en el documento .well-known/openid-configuration de tu proveedor. OIDC_DISPLAY_NAME es el texto del botón de acceso.

Comprueba que Compose interpreta bien el archivo y sustituye la contraseña de PostgreSQL:

docker compose config --quiet && echo "configuración correcta"
configuración correcta

Paso 4: Arrancar Outline

Descarga las imágenes y levanta los tres servicios en segundo plano:

docker compose up -d

Comprueba su estado. PostgreSQL y Redis deben aparecer como healthy:

docker compose ps
NAME                 IMAGE                        SERVICE    STATUS
outline-outline-1    outlinewiki/outline:latest   outline    Up 30 seconds
outline-postgres-1   postgres:16                  postgres   Up 41 seconds (healthy)
outline-redis-1      redis:7                      redis      Up 41 seconds (healthy)

En el primer arranque Outline crea las tablas de la base de datos. Revisa los logs hasta que no aparezcan errores:

docker compose logs --tail 30 outline

Si ves errores de conexión a la base de datos, revisa que DATABASE_URL y POSTGRES_PASSWORD contienen la misma contraseña.

Paso 5: Configurar Nginx como proxy inverso

Instala Nginx:

sudo apt update
sudo apt install nginx

Crea el bloque de servidor. Outline usa WebSockets para la edición colaborativa, así que el proxy debe reenviar las cabeceras Upgrade y Connection:

sudo nano /etc/nginx/sites-available/outline
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 "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;
    }
}

Activa el sitio y comprueba la sintaxis:

sudo ln -s /etc/nginx/sites-available/outline /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx

Abre los puertos en UFW si lo usas:

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Paso 6: Activar HTTPS con Let's Encrypt

Instala Certbot y solicita el certificado. El plugin de Nginx añade la configuración TLS y la redirección de HTTP a HTTPS:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your_domain

Comprueba que la renovación automática funciona:

sudo certbot renew --dry-run

Verifica que Outline responde por HTTPS:

curl -sI https://your_domain | head -1
HTTP/1.1 200 OK

Paso 7: Iniciar sesión y crear el espacio de trabajo

Abre https://your_domain en el navegador. Verás el botón con el texto de OIDC_DISPLAY_NAME; al pulsarlo se te redirigirá al proveedor de identidad y, al volver, Outline creará el espacio de trabajo. El primer usuario que accede queda como administrador.

Desde Ajustes puedes cambiar el nombre y el logotipo del espacio de trabajo, restringir los dominios de correo permitidos y crear colecciones para cada equipo.

Para enviar invitaciones y notificaciones por correo, añade los datos de tu servidor SMTP a .env:

SMTP_HOST=smtp.your_mail_provider.com
SMTP_PORT=587
SMTP_USERNAME=your_smtp_user
SMTP_PASSWORD=your_smtp_password
SMTP_FROM_EMAIL=wiki@your_domain

Tras cualquier cambio en .env, recrea el contenedor para que lea las variables nuevas; un simple restart no las recarga:

docker compose up -d --force-recreate outline

Paso 8: Programar copias de seguridad

Los datos de Outline están en dos sitios: la base de datos PostgreSQL y el volumen con los archivos subidos. Comprueba el nombre real del volumen:

docker volume ls --filter name=outline
DRIVER    VOLUME NAME
local     outline_database-data
local     outline_storage-data

Crea un script de copia de seguridad:

sudo nano /usr/local/bin/outline-backup
#!/usr/bin/env bash
set -euo pipefail

BACKUP_DIR="/var/backups/outline"
COMPOSE_DIR="/opt/outline"
STAMP="$(date +%F_%H%M)"

mkdir -p "$BACKUP_DIR"
chmod 700 "$BACKUP_DIR"
cd "$COMPOSE_DIR"

docker compose exec -T postgres pg_dump -U outline 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 .

cp .env "$BACKUP_DIR/outline-env-$STAMP"
chmod 600 "$BACKUP_DIR/outline-env-$STAMP"

find "$BACKUP_DIR" -type f -mtime +14 -delete

Hazlo ejecutable, pruébalo y prográmalo cada noche:

sudo chmod 750 /usr/local/bin/outline-backup
sudo /usr/local/bin/outline-backup
sudo ls -lh /var/backups/outline
echo '30 2 * * * root /usr/local/bin/outline-backup' | sudo tee /etc/cron.d/outline-backup

Guarda una copia de .env: sin SECRET_KEY no podrás restaurar las sesiones ni los datos cifrados de las integraciones.

Actualizar Outline

Haz una copia de seguridad, descarga la imagen nueva y recrea el contenedor. Outline aplica las migraciones de base de datos al arrancar:

cd /opt/outline
sudo /usr/local/bin/outline-backup
docker compose pull
docker compose up -d
docker image prune -f

En producción es preferible fijar una versión concreta en image: (por ejemplo, la etiqueta publicada en las releases de GitHub) en lugar de latest, para actualizar solo cuando tú lo decidas.

Solución de problemas

  • Tras iniciar sesión vuelves a la pantalla de acceso: URL en .env no coincide con la dirección real, o Nginx no envía X-Forwarded-Proto. Corrige y recrea el contenedor.
  • El proveedor OIDC muestra "redirect_uri mismatch": la URL de callback registrada debe ser exactamente https://your_domain/auth/oidc.callback.
  • Los cambios no se sincronizan entre usuarios: faltan las cabeceras Upgrade y Connection en Nginx.
  • Error 413 al subir archivos: aumenta client_max_body_size en Nginx.

Conclusión

Outline está funcionando en Ubuntu 24.04 con Docker Compose, detrás de Nginx con HTTPS, con autenticación OIDC y copias de seguridad diarias. Como siguientes pasos puedes mover los adjuntos a un almacenamiento compatible con S3, conectar integraciones como Slack desde los ajustes y copiar las copias de seguridad a otro servidor.