MAATRIX / Блог / Outline в Docker Compose: готовый файл

Outline в Docker Compose: готовый файл

MAATRIX

Команда растёт, и заметки в личных Google Docs, скриншоты в чатах и файлы «финал_v3.docx» перестают работать как база знаний — искать в них невозможно, а доступы никто не помнит. Notion решает это удобно, но данные лежат на чужих серверах, а цена за место растёт с числом человек в команде. Outline — self-hosted вики с Markdown-редактором, быстрым полнотекстовым поиском и структурой из коллекций и документов: ниже рабочий docker-compose.yml, чтобы поднять её на своём сервере за один вечер. Уточним сразу: речь о вики-движке getoutline.com, а не об Outline VPN от Jigsaw — это два разных продукта с одинаковым названием, ничего общего в коде и назначении у них нет.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Чем Outline отличается от Notion и когда он оправдан

Outline — это не клон Notion, а более узкий инструмент: документы, коллекции (папки верхнего уровня), вложенные страницы, комментарии и полнотекстовый поиск по всей базе. Нет баз данных со связями, канбан-досок и формул — если команде нужен именно такой конструктор, лучше смотреть в сторону NocoDB или Baserow. Зато у Outline быстрый и предсказуемый Markdown-редактор, который не тормозит на длинных документах, и API, которым удобно наполнять базу из скриптов.

Практические причины ставить self-hosted вместо облачного Notion:

  • Данные остаются на вашем сервере. Для команды с внутренней документацией, доступами и паролями это не абстрактный принцип, а требование безопасности.
  • Стоимость не растёт с числом пользователей. В облачных тарифах цена почти всегда за место; на своём сервере лимит — это диск и RAM, а не число сотрудников.
  • Единая авторизация. Outline подключается к корпоративному OIDC/Google/Slack-логину — не нужно заводить отдельный пароль для базы знаний.

Честный минус: разворачивать и поддерживать стек — ваша ответственность, включая бэкапы и обновления. Если это лишняя головная боль, облачный тариф Outline или Notion объективно проще. Дальше — про то, как эту ответственность свести к минимуму.

Из чего состоит стек

Outline — не один контейнер, а связка из нескольких сервисов, и это стоит понимать до старта:

КомпонентРольОбязателен?
outlineсамо приложение (Node.js)да
PostgreSQL 12+основная база: документы, права, история правокда
Redis 6+очереди задач, сессии, pub/sub для совместного редактированияда
Хранилище файлов (локальный диск или S3-совместимое)вложения, картинки, экспортда, один из двух вариантов
SMTP-серверписьма о упоминаниях, экспорт, магическая ссылка входанет, но без него часть уведомлений не работает

Локальное хранение файлов проще для старта — Outline пишет вложения в примонтированный том. Но если вы уже держите S3-совместимое хранилище для бэкапов или других сервисов, разумнее сразу подключить его через переменные AWS_* — ниже покажу оба варианта. Развернуть свой S3-эндпоинт можно тем же вечером: у нас есть отдельный готовый compose-файл для MinIO.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Готовый docker-compose.yml

Рабочий конфиг с Postgres, Redis и локальным хранением файлов — для старта этого достаточно:

services:
  outline:
    image: docker.getoutline.com/outlinewiki/outline:latest
    container_name: outline
    restart: unless-stopped
    env_file: ./.env
    ports:
      - "127.0.0.1:3000:3000"
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    volumes:
      - outline_data:/var/lib/outline/data

  redis:
    image: redis:7-alpine
    container_name: outline_redis
    restart: unless-stopped
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

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

volumes:
  outline_data:
  redis_data:
  postgres_data:

Порт приложения намеренно привязан к 127.0.0.1:3000 — наружу его отдаёт reverse proxy по HTTPS, напрямую в интернет контейнер не смотрит. Официальный образ публикуется в реестре docker.getoutline.com — перед боевым запуском откройте страницу релизов на GitHub и замените latest на конкретный тег: так обновления происходят осознанно, а не при случайном docker compose pull.

Файл .env: обязательные переменные

Создайте .env рядом с docker-compose.yml. Два секрета сгенерируйте сами:

openssl rand -hex 32   # для SECRET_KEY
openssl rand -hex 32   # для UTILS_SECRET

Минимальный рабочий набор:

NODE_ENV=production
SECRET_KEY=<результат первой команды>
UTILS_SECRET=<результат второй команды>

URL=https://wiki.example.com
PORT=3000
FORCE_HTTPS=true

DATABASE_URL=postgres://outline:${POSTGRES_PASSWORD}@postgres:5432/outline
DATABASE_URL_TEST=postgres://outline:${POSTGRES_PASSWORD}@postgres:5432/outline-test
PGSSLMODE=disable

REDIS_URL=redis://redis:6379

POSTGRES_PASSWORD=<длинный случайный пароль>

FILE_STORAGE=local
FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data
FILE_STORAGE_UPLOAD_MAX_SIZE=26214400

Для S3-совместимого хранилища (например, свой MinIO) замените блок FILE_STORAGE:

FILE_STORAGE=s3
AWS_ACCESS_KEY_ID=<ключ>
AWS_SECRET_ACCESS_KEY=<секрет>
AWS_REGION=us-east-1
AWS_S3_UPLOAD_BUCKET_URL=https://s3.example.com
AWS_S3_UPLOAD_BUCKET_NAME=outline
AWS_S3_FORCE_PATH_STYLE=true
AWS_S3_ACL=private

AWS_S3_FORCE_PATH_STYLE=true обязателен для MinIO и большинства не-AWS хранилищ — без этого запросы уходят на несуществующий поддомен вида bucket.s3.example.com, которого у вас нет.

Авторизация: без неё Outline не запустится

Отличие от типичного self-hosted сервиса: Outline требует хотя бы один настроенный провайдер входа ещё до первого запуска — просто логина и пароля из коробки нет. Варианты, которые можно комбинировать:

  • Google WorkspaceGOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, вход ограничивается доменом рабочей почты.
  • SlackSLACK_CLIENT_ID, SLACK_CLIENT_SECRET, удобно, если команда уже живёт в Slack.
  • Microsoft/Azure ADAZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_RESOURCE_APP_ID.
  • Универсальный OIDCOIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC_AUTH_URI, OIDC_TOKEN_URI, OIDC_USERINFO_URI — подходит для своего Keycloak, Authentik или другого IdP, если хочется полностью независимую от больших платформ авторизацию.

Каждый провайдер требует зарегистрировать OAuth-приложение на стороне Google/Slack/Microsoft/вашего IdP с redirect_uri вида https://wiki.example.com/auth/google.callback (для остальных провайдеров — по аналогии, меняется только последний сегмент). Без правильного URL в .env редирект после входа не сработает — переменная должна точно совпадать с доменом, по которому открывается вики.

Reverse proxy, HTTPS и бэкапы

Outline использует WebSocket для совместного редактирования документов в реальном времени — в конфиге nginx это нужно явно учесть:

server {
    listen 443 ssl http2;
    server_name wiki.example.com;

    ssl_certificate     /etc/letsencrypt/live/wiki.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/wiki.example.com/privkey.pem;

    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 https;
    }
}

Про сам процесс настройки nginx как обратного прокси и получение сертификата Let's Encrypt — в отдельных пошаговых статьях: nginx как reverse proxy и общая база по Docker Compose для продакшена, если стек ставится с нуля.

Бэкап — это два независимых объекта: база данных и файлы вложений.

# дамп базы
docker exec outline_postgres pg_dump -U outline outline | gzip > outline_$(date +%F).sql.gz

# том с вложениями (при локальном хранении)
docker run --rm -v outline_outline_data:/data -v $(pwd):/backup alpine \
  tar czf /backup/outline_files_$(date +%F).tar.gz -C /data .

Оба архива стоит выгружать за пределы сервера — вручную по расписанию через cron или инструментом вроде Restic, который умеет шифровать и складывать бэкапы прямо в S3-хранилище. Если вложения уже лежат в S3 (MinIO или облачный), то бэкапить их отдельно не нужно — достаточно бэкапа самого бакета и базы данных.

Обновление — стандартная процедура для стека на Docker Compose: смените тег образа в docker-compose.yml, снимите бэкап базы и выполните docker compose pull && docker compose up -d. Миграции базы данных Outline применяет автоматически при старте контейнера.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Outline бесплатен для self-hosted?

Да, код открыт (BSL с переходом в Apache 2.0 через несколько лет после релиза версии), self-hosted развёртывание бесплатно для собственного использования. Ограничения лицензии касаются перепродажи Outline как сервиса — уточните текущие условия в репозитории проекта перед коммерческим использованием.

Можно запустить без домена, просто по IP?

Технически да, но URL в .env должен точно совпадать с адресом, по которому открывается сайт, а часть провайдеров авторизации (например, Google) требует HTTPS и реального домена для redirect_uri — без домена рабочей останется разве что связка с локальным OIDC.

Сколько RAM нужно на старте?

Для команды до 20-30 человек хватает 2 ГБ RAM на весь стек (Outline + Postgres + Redis) с запасом; точная цифра зависит от объёма базы и параллельных редакторов, так что относитесь к этому как к ориентиру, а не гарантии.

Есть ли миграция из Notion?

Outline умеет импортировать экспорт Notion в формате Markdown/HTML через раздел настроек «Import» — структура коллекций и страниц переносится, но встроенные базы данных Notion (не Markdown-документы) при импорте не сохраняются как интерактивные таблицы.

Как включить полнотекстовый поиск?

Он включён по умолчанию и работает через встроенный поиск PostgreSQL (tsvector) — отдельного сервиса вроде Elasticsearch поднимать не нужно, поиск индексируется автоматически при сохранении документа.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →