Outline — self-hosted wiki/knowledge base с Notion-style блочным редактором, OIDC SSO, S3-совместимым backend'ом для аттачей. Лицензия BSL-1.1 — для внутренней эксплуатации бесплатна.
См. также k8s (кластер) и Authentik (IdP — OIDC-провайдер для логина).
Предусловия: см. k8s (нужны default StorageClass, ingress-nginx, cert-manager) и Authentik (OIDC-application с client_id/secret уже создано).
# 1. Bitnami subchart'ы для PG/Redis/Minio (см. ниже про "Bitnami legacy")
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update bitnami
# 2. Namespace
kubectl create namespace outline
# 3. Сгенерить секреты
OUTLINE_SECRET_KEY=$(openssl rand -hex 32)
OUTLINE_UTILS_SECRET=$(openssl rand -hex 32)
OUTLINE_PG_PASSWORD=$(openssl rand -base64 24 | tr -d '\n=')
OUTLINE_REDIS_PASSWORD=$(openssl rand -base64 24 | tr -d '\n=')
OUTLINE_MINIO_PASSWORD=$(openssl rand -base64 24 | tr -d '\n=')
# 4. PostgreSQL — с переключением на bitnamilegacy/* (см. раздел про Bitnami)
helm install outline-pg bitnami/postgresql -n outline --wait --timeout 10m \
--set global.security.allowInsecureImages=true \
--set image.repository=bitnamilegacy/postgresql \
--set volumePermissions.image.repository=bitnamilegacy/os-shell \
--set metrics.image.repository=bitnamilegacy/postgres-exporter \
--set auth.username=outline \
--set auth.database=outline \
--set auth.password="$OUTLINE_PG_PASSWORD" \
--set primary.persistence.size=10Gi
# 5. Redis
helm install outline-redis bitnami/redis -n outline --wait --timeout 10m \
--set global.security.allowInsecureImages=true \
--set image.repository=bitnamilegacy/redis \
--set sentinel.image.repository=bitnamilegacy/redis-sentinel \
--set metrics.image.repository=bitnamilegacy/redis-exporter \
--set architecture=standalone \
--set auth.password="$OUTLINE_REDIS_PASSWORD" \
--set master.persistence.size=2Gi
# 6. Minio (бакет создаётся при первом старте через defaultBuckets)
helm install outline-minio bitnami/minio -n outline --wait --timeout 10m \
--set global.security.allowInsecureImages=true \
--set image.repository=bitnamilegacy/minio \
--set clientImage.repository=bitnamilegacy/minio-client \
--set auth.rootUser=outline \
--set auth.rootPassword="$OUTLINE_MINIO_PASSWORD" \
--set defaultBuckets=outline-uploads \
--set persistence.size=20Gi
# 7. Secret + Deployment + Service + Ingress для самого Outline
# Полный набор env-переменных см. в roles/outline/tasks/main.yml ansible-проекта.
# Главные блоки:
# - SECRET_KEY, UTILS_SECRET (random hex 32)
# - DATABASE_URL = postgres://outline:PASS@outline-pg-postgresql.outline.svc:5432/outline?sslmode=disable
# - REDIS_URL = redis://default:PASS@outline-redis-master.outline.svc:6379
# - URL = https://wiki.example.com
# - FILE_STORAGE=s3 + AWS_* (endpoint = http://outline-minio.outline.svc:9000)
# - OIDC_CLIENT_ID/SECRET + OIDC_AUTH_URI/TOKEN_URI/USERINFO_URI/LOGOUT_URI
✅ Под Hetzner-кластер всё это уже автоматизировано в infra/ansible/hetzner/k8s/roles/outline/.
cd /mnt/c/ai/claude/infra/ansible/hetzner/k8s
# 1. секреты в vault (один раз)
./bootstrap-secrets.sh
# 2. Authentik сначала (см. [[Authentik]])
ansible-playbook install-wiki.yml --tags=authentik
# 3. в Authentik UI создать OAuth2/OpenID Provider + Application для Outline
# (см. [[Authentik]] раздел "OIDC-приложение")
# Redirect URI: https://wiki.example.com/auth/oidc.callback
# Application slug: outline (важно — совпадает с outline_authentik_app_slug)
# 4. подставить client_id/secret в vault
ansible-vault edit group_vars/all/vault.yml
# заменить REPLACE_AFTER_AUTHENTIK_UI на реальные значения
# 5. Outline
ansible-playbook install-wiki.yml --tags=outline
⚠️ С 28 августа 2025 Bitnami провёл миграцию Docker Hub: репозиторий docker.io/bitnami/* оставлен только под платный «Bitnami Secure Images» (требует auth), а все исторические/публичные образы переехали в docker.io/bitnamilegacy/*. Чарты при этом продолжают по умолчанию указывать на bitnami/* — pod падает с:
Failed to pull image "docker.io/bitnami/postgresql:17.6.0-debian-12-r4":
failed to resolve reference "docker.io/bitnami/postgresql:17.6.0-debian-12-r4": not found
Решение для каждого Bitnami-чарта в values задать:
global:
security:
allowInsecureImages: true # снимает enforcement-проверку чарта
image:
repository: bitnamilegacy/<name> # переключает основной pull на legacy
# вспомогательные образы (имена контейнеров зависят от чарта):
volumePermissions:
image:
repository: bitnamilegacy/os-shell
metrics:
image:
repository: bitnamilegacy/postgres-exporter # для PG
# bitnamilegacy/redis-exporter — для Redis
sentinel:
image:
repository: bitnamilegacy/redis-sentinel # Redis с sentinel
clientImage:
repository: bitnamilegacy/minio-client # Minio
⚠️ Если ставить Authentik (см. Authentik) — у его helm-чарта allowInsecureImages: true уже включено в дефолтных values, его внутренние PG/Redis subchart'ы поднимаются без правок.
✅ Долгосрочно — либо платить Bitnami за secure-images, либо перейти на не-Bitnami чарты:
redis/redis chart или просто StatefulSet с redis:7-alpinehttps://operator.min.io/При первом OIDC-логине Outline создаёт workspace с именем по OIDC_DISPLAY_NAME (у меня по умолчанию был Authentik default). Поменять:
Settings → General → Workspace name
Заодно в Settings → Details:
По умолчанию любой пользователь Authentik может зайти в твой Outline и автоматически создать аккаунт. Если хочется ограничить:
Settings → Security → SSO restrict to domains → добавить домены вроде ivstech.org (по email-полю из OIDC claim).
Альтернативно — в Authentik на самом application привязать Group binding (только конкретная группа юзеров видит и может логиниться).
Settings → Import:
.md файлы и .zip с папками)⚠️ При импорте markdown Outline режет переносы по своей логике — таблицы, mermaid и embed'ы лучше предварительно проверить визуально.
Импорт через API — для batch-миграции из vault'а:
TOKEN="ol_api_XXXXXXXX..." # Settings → API Tokens → Create
COLLECTION_ID="$(curl -s -H "Authorization: Bearer $TOKEN" \
https://wiki.example.com/api/collections.list \
| jq -r '.data[] | select(.name=="Linux") | .id')"
for f in /mnt/x/storage/docs/obsidian/docs/Linux/*.md; do
title=$(basename "$f" .md)
body=$(jq -Rs . < "$f")
curl -s -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-X POST https://wiki.example.com/api/documents.create \
-d "{\"title\":\"$title\",\"text\":$body,\"collectionId\":\"$COLLECTION_ID\",\"publish\":true}" \
| jq -r '.data.url'
done
⌘K / Ctrl+K — command palette (поиск по всему, navigation)/ в редакторе — slash-меню для блоков (heading, code, image, embed, mermaid)[[ — вставка ссылки на другой документ⌘+\ — toggle сайдбара❌ ImagePullBackOff на Bitnami-подах (PG/Redis/Minio): docker.io/bitnami/...: not found Решение См. раздел «Особенности Bitnami образов» выше — переключить image.repository на bitnamilegacy/* и включить global.security.allowInsecureImages: true.
❌ Outline pod лежит CrashLoopBackOff, в логах ECONNREFUSED ... postgres-pg-postgresql.outline.svc:5432 Решение Проверь, действительно ли поднялся PG: kubectl -n outline get pods | grep postgresql. Если он Pending — нет StorageClass (см. в k8s раздел про CSI). Если CrashLoopBackOff сам PG — образ из Bitnami legacy (предыдущий пункт) и/или поломанные PVC (kubectl -n outline delete pvc --all и переставить).
❌ Логин через OIDC возвращает в Outline с Error: Invalid request, code=... Решение Несовпадение redirect URI в Authentik (Provider settings) и того, который Outline посылает. Authentik должен иметь в Redirect URIs ровно https://wiki.example.com/auth/oidc.callback (без trailing slash). Сверь.
❌ Авто-логин уводит на Authentik и тут же возвращает с ошибкой, без шанса нажать «Continue» Решение Чаще всего — OIDC_CLIENT_ID или OIDC_CLIENT_SECRET в Outline Secret не совпадает с тем, что в Authentik Provider. Сверить:
kubectl -n outline get secret outline -o jsonpath='{.data.OIDC_CLIENT_ID}' | base64 -d; echo
kubectl -n outline get secret outline -o jsonpath='{.data.OIDC_CLIENT_SECRET}' | base64 -d; echo
И сравнить с Provider'ом в Authentik UI. После правки — kubectl -n outline rollout restart deploy/outline.
❌ Аттачи не загружаются: 502 / Failed to upload / в логах S3 ... NoSuchBucket Решение Bucket не создался в Minio. Проверь:
kubectl -n outline run mc --rm -it --image=docker.io/bitnamilegacy/minio-client --restart=Never -- sh
# внутри:
mc alias set m http://outline-minio.outline.svc:9000 outline <ROOT_PASSWORD>
mc ls m
mc mb m/outline-uploads # если bucket'а нет — создать вручную