Очередная статья про настройку Outline + KeyCloak. С одной стороны, статьи в сети есть. С другой стороны - начинаешь по ним делать и выплывают подводные камни, которые в статьях почему то не приведены. После определенного периодического мучения с установкой данного продукта решил собрать в кучу все мысли и действия.
Первоисточник: Основной алгоритм был взят из статьи.
Первичная подготовка системы
Выбираем, что нам по душе - Debian 12 или Ubuntu Server. Алгоритм в этих вариантах один и тотже.
Устанавливаем Docker согласно документации: Docker_on_Debian или Docker_on_Ubuntu.
Придумываем и регистрируем во внешних DNS-серверах три DNS-записи для трех решений:
wiki.<наш домен>
kk.<наш домен>
minio.<наш домен>
ВАЖНО: Если на Linux машине IP-адрес серый (но в нас есть DNAT портов 80/443 либо Reverse Proxy), обязательно нужно в файле /etc/hosts прописать соответствие серого IP-адреса и созданным трем DNS-записям. Вообще в любом варианте (белый IP на интерфейсе) можно это сделать, лишним не будет. Если этот шаг упустить - KeyCloak аутентификация у меня не работает с Outline.
Установка KeyCloak
Создаем каталог для размещения сценария для Docker:
mkdir -pv /opt/keycloak
nano /opt/keycloak/docker-compose.yml
Заполняем файл, меняем WEB-имя сервера и пароль доступа к админской части:
version: '3'
volumes:
keycloak-db:
services:
keycloak:
image: quay.io/keycloak/keycloak:latest
environment:
KC_PROXY: edge
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: XXXXXXXXXX
KC_HOSTNAME: kk.vdsina.vershininegor.site
KC_HOSTNAME_STRICT_HTTPS: 1
KC_HOSTNAME_STRICT: 1
volumes:
- keycloak-db:/opt/keycloak/data/h2
ports:
- 7214:8080
command: "start --optimized"
Сохраняем, далее, переходим в каталог /opt/keycloak/ и запускаем установку контейнера:
cd /opt/keycloak/
docker compose up -d
Ожидаемый вывод, если у нас есть Интернет, и мы правильно установили Docker:
root@ubuntu:/opt/keycloak# docker compose up -d
[+] Running 5/5
✔ keycloak 4 layers [⣿⣿⣿⣿] 0B/0B Pulled 15.3s
✔ da5b6ed7dedb Pull complete 2.2s
✔ 235cc15c2bca Pull complete 6.5s
✔ 33a5d0f592f8 Pull complete 8.5s
✔ 881ee45db5ad Pull complete 8.5s
[+] Running 3/3
✔ Network keycloak_default Created 0.1s
✔ Volume "keycloak_keycloak-db" Created 0.0s
✔ Container keycloak-keycloak-1 Started
После запуска смотрим статус контейнера командой:
docker compose ps -a
Через некоторое время видим, что контейнер не запущен, статус остановки Exited:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
keycloak-keycloak-1 quay.io/keycloak/keycloak:latest "/opt/keycloak/bin/k…" keycloak 17 minutes ago Exited (1) 17 minutes ago
Смотрим журнал контейнера (docker logs <имя контейнера>):
2023-08-15 09:14:58,626 WARN [io.agroal.pool] (agroal-11) Datasource '<default>': Error opening database: "Could not save properties /opt/keycloak/data/h2/keycloakdb.lock.db" [8000-220]
2023-08-15 09:14:58,653 INFO [org.infinispan.CLUSTER] (main) ISPN000080: Disconnecting JGroups channel `ISPN`
2023-08-15 09:14:58,695 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Failed to start server in (production) mode
2023-08-15 09:14:58,696 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Failed to obtain JDBC connection
2023-08-15 09:14:58,696 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Error opening database: "Could not save properties /opt/keycloak/data/h2/keycloakdb.lock.db" [8000-220]
2023-08-15 09:14:58,696 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: /opt/keycloak/data/h2/keycloakdb.lock.db
2023-08-15 09:14:58,698 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) For more details run the same command passing the '--verbose' option. Also you can use '--help' to see the details about the usage of the particular command.
Исправляется следующей командой:
chmod 777 /var/lib/docker/volumes/keycloak_keycloak-db/_data/
Останавливаем и снова запускаем контейнер:
cd /opt/keycloak/
docker compose down
docker compose up -d
Теперь команды docker compose ps -a и lsof -i -nP должны показывать, что контейнер с KeyCloak работает и порты доступа открыты.
SSL/TLS сертификаты для Nginx
KeyCloak и Outline по умолчанию настроены на работу только по HTTPS. При этом они также не доверяют самоподписанным сертификатам и заставить их работать у меня не получилось до конца (хотя попытки были и кое какой прогресс был).
Поэтому нам необходим белый IP, публичные DNS-записи и утилита python3-certbot. Устанавливаем, запускаем (certbot certonly), получаем на 3 месяца сертификат на три публичных DNS-записи.
Установка Nginx
Во многих статьях используют Docker контейнер с Nginx Proxy Manager, который дает GUI для настройки и сам способен автоматически продлять Les't Encrypt сертификаты. В прошлом я его использовал, в последний раз решил от него отказаться в пользу установки Nginx на базовую систему (потому что захотелось).
apt install nginx
cd /etc/nginx/sites-enabled
Настройка Nginx для Outline, KeyCloak и MinIO
Создаем следующие конфигурации - /etc/nginx/sites-enabled/keycloak.conf:
server {
listen 80;
server_name kk.vdsina.vershininegor.site;
rewrite ^ https://$server_name$request_uri? permanent;
}
server {
listen 443 ssl;
server_name kk.vdsina.vershininegor.site;
# Logging (optional, but probably want it for debugging)
access_log /var/log/nginx/keycloak-access.log;
error_log /var/log/nginx/keycloak-error.log info;
## Keep alive timeout set to a greater value for SSL/TLS.
keepalive_timeout 75 75;
# Locations of certs using Certbot
ssl_certificate /etc/letsencrypt/live/wiki.vdsina.vershininegor.site/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/wiki.vdsina.vershininegor.site/privkey.pem;
ssl_session_timeout 5m;
# Forces browsers to redirect to HTTPS themselves for 31536000 seconds (1 year).
# includeSubDomains will cause this to upgrade HTTP on all subdomains of the given domain.
# preload adds your domain to a list of domains for browsers to automatically upgrade to HTTPS, no mattter what.
# always will append the header no matter the return code.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# SSO requests tend to be very long, will fail on default settings.
proxy_buffer_size 12k;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto https;
location /js/ {
proxy_pass http://127.0.0.1:7214;
}
location /realms/ {
proxy_pass http://127.0.0.1:7214;
}
location /auth/ {
proxy_pass http://127.0.0.1:7214;
}
location /resources/ {
proxy_pass http://127.0.0.1:7214;
}
location /robots.txt {
proxy_pass http://127.0.0.1:7214;
}
# We don't really care about anything else.
location / {
return 404;
}
# -------------------
# I recommend deleting the /admin/ endpoint once done for security reasons.
# -------------------
location /admin/ {
proxy_pass http://127.0.0.1:7214;
}
}
/etc/nginx/sites-enabled/minio.conf
server {
listen 80;
server_name minio.vdsina.vershininegor.site;
rewrite ^ https://$server_name$request_uri? permanent;
}
server {
listen 443 ssl;
server_name minio.vdsina.vershininegor.site;
# Logging (optional, but probably want it for debugging)
access_log /var/log/nginx/minio-access.log;
error_log /var/log/nginx/minio-error.log info;
## Keep alive timeout set to a greater value for SSL/TLS.
keepalive_timeout 75 75;
# Locations of certs using Certbot
ssl_certificate /etc/letsencrypt/live/wiki.vdsina.vershininegor.site/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/wiki.vdsina.vershininegor.site/privkey.pem;
ssl_session_timeout 5m;
# Forces browsers to redirect to HTTPS themselves for 31536000 seconds (1 year).
# includeSubDomains will cause this to upgrade HTTP on all subdomains of the given domain.
# preload adds your domain to a list of domains for browsers to automatically upgrade to HTTPS, no mattter what.
# always will append the header no matter the return code.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# SSO requests tend to be very long, will fail on default settings.
proxy_buffer_size 12k;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto https;
ignore_invalid_headers off;
client_max_body_size 0;
proxy_buffering off;
proxy_request_buffering off;
location / {
proxy_set_header Host $http_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_connect_timeout 300;
proxy_http_version 1.1;
proxy_set_header Connection "";
chunked_transfer_encoding off;
proxy_pass http://127.0.0.1:7216;
}
}
/etc/nginx/sites-enabled/outline.conf
server {
listen 80;
server_name wiki.vdsina.vershininegor.site;
rewrite ^ https://$server_name$request_uri? permanent;
}
server {
listen 443 ssl;
server_name wiki.vdsina.vershininegor.site;
# Logging (optional, but probably want it for debugging)
access_log /var/log/nginx/outline-access.log;
error_log /var/log/nginx/outline-error.log info;
## Keep alive timeout set to a greater value for SSL/TLS.
keepalive_timeout 75 75;
# Locations of certs using Certbot
ssl_certificate /etc/letsencrypt/live/wiki.vdsina.vershininegor.site/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/wiki.vdsina.vershininegor.site/privkey.pem;
ssl_session_timeout 5m;
# Forces browsers to redirect to HTTPS themselves for 31536000 seconds (1 year).
# includeSubDomains will cause this to upgrade HTTP on all subdomains of the given domain.
# preload adds your domain to a list of domains for browsers to automatically upgrade to HTTPS, no mattter what.
# always will append the header no matter the return code.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# SSO requests tend to be very long, will fail on default settings.
proxy_buffer_size 12k;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto https;
location / {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
# Set to the correct ports for Outline
proxy_pass http://127.0.0.1:7215;
}
}
Перезапускаем Nginx:
systemctl restart nginx
Настройка KeyCloak
Входим по адресу: https://kk.<наш домен>/admin , авторизуемся учеткой admin с паролем, который задан в docker-compose.yml файле:
Создаем новый Realm с именем outline:
Находясь уже в новом созданном Realm с именем outline, создаем нового клиента (это наш сайт с Outline):
Указываем имя, описание и ID - outline-wiki :
Включаем клиентскую аутентификацию и отключаем прямой вход:
Указываем ряд URL-адресов нашей WiKi:
Настройка KeyCloak - вторая часть
Теперь нам нужно сохранить себе мастер-ключ для взаймодействия с этим клиентом. Переходим в раздел Credentials и копируем себе ключ, который сгенерировался при создании клиента KeyCloak:
Теперь необходимо создать пользователя в KeyCloak - с его помощью мы будем авторизовываться и работать в Outline Wiki.
В левом фрейме переходим в раздел: Users и добавляем нового пользователя: Add User. Логин и email должны совпадать.
После создания пользователя у него не задан пароль - необходимо это исправить в разделе Credentials через кнопку Set password:
На этом работа с KeyCloak закончена. Других пользователей Outline создавать аналогично.
Запуск контейнеров с PostgreSQL, Redis, MinIO и Outline
Создаем нужный каталог и файлы:
mkdir -pv /opt/outline
touch /opt/outline/docker-compose.yml
touch /opt/outline/docker.env
Содержимое файла docker-compose.yml:
version: "3"
services:
outline:
image: outlinewiki/outline:latest
env_file: ./docker.env
networks:
- outline-network
ports:
- "7215:3000"
depends_on:
- postgres
- redis
- minio
command: sh -c "yarn db:migrate --env production-ssl-disabled && yarn start"
redis:
image: redis
env_file: ./docker.env
networks:
- outline-network
volumes:
- ./redis.conf:/redis.conf
command: ["redis-server", "/redis.conf"]
postgres:
image: postgres
env_file: ./docker.env
networks:
- outline-network
volumes:
- outline-postgres-data:/var/lib/postgresql/data
minio:
image: minio/minio:latest
env_file: ./docker.env
networks:
- outline-network
ports:
- "7216:9000"
- "9001:9001"
deploy:
restart_policy:
condition: on-failure
volumes:
- outline-minio-data:/data
entrypoint: sh
command: -c 'minio server --console-address ":9001" /data'
volumes:
outline-minio-data:
outline-postgres-data:
networks:
outline-network:
name: outlinewiki-network
Содержимое с настройками (будем дальше несколько раз менять) - docker.env :
# Fill these out with "pwgen 64 1" or "openssl rand -hex 32".
SECRET_KEY=2787d5895f5a61235eb73e8dc1712e57bbfa4a4d7fc3a8bf10d2ed4570c0869b
UTILS_SECRET=d679896a4576c0887862b72b7bee1ae3c68d050d7f40118678d089675fefd367
# Please see "Enviroment Variables" for more information.
# Make sure to change "user" and "pass".
POSTGRES_USER=admin
POSTGRES_PASSWORD=XXXXXXXXXX
POSTGRES_DB=outline
# Please see "Enviroment Variables" for more information.
# Make sure to change "user" and "pass".
# If you changed POSTGRES_DB, change "outline", too.
DATABASE_URL=postgres://admin:XXXXXXXXXX@postgres:5432/outline
# Was in the official Docker.env. Probably not needed?
DATABASE_URL_TEST=postgres://admin:XXXXXXXXXX@postgres:5432/outline-test
# This is the domain name to access Outline. Include the "https://"
URL=https://wiki.vdsina.vershininegor.site
# Please see "Enviroment Variables" for more information.
# Make sure to change "user" and "pass".
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=XXXXXXXXXX
# You will need to get this from the Minio admin panel.
AWS_ACCESS_KEY_ID=DpzbsYrmOnAcbSGq
AWS_SECRET_ACCESS_KEY=ESMxba21uVn0NXK7UzzXaJhEmfvYJT9l
AWS_REGION=us-east-1
AWS_S3_UPLOAD_BUCKET_URL=https://minio.vdsina.vershininegor.site/
AWS_S3_UPLOAD_BUCKET_NAME=datawiki
AWS_S3_UPLOAD_MAX_SIZE=26214400
## Probably shouldn't change these
AWS_S3_FORCE_PATH_STYLE=true
AWS_S3_ACL=private
# You will need to get this from the Keycloak admin panel. Please see "Keycloak OIDC Setup".
OIDC_CLIENT_ID=outline-wiki
OIDC_CLIENT_SECRET=Kw4NvTB1nEB89iTSzQ91IHRk4k3smrqh
OIDC_AUTH_URI=https://kk.vdsina.vershininegor.site/realms/outline/protocol/openid-connect/auth
OIDC_TOKEN_URI=https://kk.vdsina.vershininegor.site/realms/outline/protocol/openid-connect/token
OIDC_USERINFO_URI=https://kk.vdsina.vershininegor.site/realms/outline/protocol/openid-connect/userinfo
## Changes what shows up on the login button.
OIDC_DISPLAY_NAME=Keycloak
## Probably shouldn't change
OIDC_USERNAME_CLAIM=preferred_username
OIDC_SCOPES=openid profile email
# Telemtry?!?!! :O
# Enable if you want.
ENABLE_UPDATES=false
# Check official docs for this. Has to be with processes or whatever.
WEB_CONCURRENCY=1
# Limits size of documents (esp. with images) in (I think) bytes,
MAXIMUM_IMPORT_SIZE=5120000
# Default langauage. Supported codes at translate.getoutline.com.
DEFAULT_LANGUAGE=en_US
# ----------------------------------
# STUFF YOU PROBABLY SHOULD NOT CHANGE.
# ----------------------------------
# Self-explanatory.
NODE_ENV=production
# Docker will forward this specific port to the host as the one specified in the compose file.
PORT=3000
# Accessing self-hosetd redis through the Docker network.
REDIS_URL=redis://redis:6379
# We will be using Postgres through the Docker network. So no HTTPS.
PGSSLMODE=disable
# We will terminate SSL on nginx.
FORCE_HTTPS=false
В параметр OIDC_CLIENT_SECRET впишите ключ, который мы сохраняли сразу после создания клиента в KeyCloak (outline-wiki).
Параметры AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, AWS_S3_UPLOAD_BUCKET_NAME пока оставляем как есть, мы их исправим позже, когда установим, запустим и настроим параметры контейнера с MinIO (S3-хранилища).
Теперь необходимо запустить загрузку и запуск контейнеров:
cd /opt/outline/
docker compose up -d
Настройка MinIO
Подключаемся к серверу по адресу: http://<IP>:9001
Входим учеткой admin и паролем, который мы указали в docker.env файле.
ПЕРВЫЙ ШАГ - сменить регион расположения S3 хранилища и перезапустить сервис:
Далее жмем кнопку: Restart и дал должно из сервиса выкинуть (снова на страницу входа):
Снова входим и настраиваем.
Настройка MinIO - часть 2
Теперь создаем Bucket для хранения картинок и другого контента wiki:
Выбираем имя - datawiki. Тут есть тонкости - если выбирать имена, пересекающиеся с именами URL-адресов, будут проблемы.
В созданном Bucket создаем Access Rule:
Создаем Access Key для параметров AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY в файле docker.env:
Записываем в блокнот данные для AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY (больше их посмотреть не удастся).
Настройка MinIO закончена.
Донастройка контейнеров
Теперь нам нужно изменить содержимое файла /opt/outline/docker.env и указать параметры:
AWS_ACCESS_KEY_ID=Zk27jPsxqE0ro9B2
AWS_SECRET_ACCESS_KEY=MmqmnkUcvONVwhm8sBtTpa6wW1n2KsCj
AWS_REGION=us-east-1
AWS_S3_UPLOAD_BUCKET_URL=https://minio.vdsina.vershininegor.site/
AWS_S3_UPLOAD_BUCKET_NAME=datawiki
AWS_S3_UPLOAD_MAX_SIZE=26214400
## Probably shouldn't change these
AWS_S3_FORCE_PATH_STYLE=true
AWS_S3_ACL=private
Теперь перезапускаем контейнеры с этими параметрами:
cd /opt/outline/
docker compose down
docker dompose up -d
Проверка работы
Входим по адресу: https://wiki.vdsina.vershininegor.site.
При входе появляется кнопка - продолжить вход с помощью KeyCloak.
Авторизуемся в нем и нас пускают в Outline Wiki.
Потребление ресурсов
На самой дешевой виртуалке за 15 рублей в день (1 ядро, 2 Гб ОЗУ) это способно жить и работать при 2-3 пользователях. На холостом ходу Active ОЗУ чуть больше 1,2 Гб.
Личное мнение автора
С 2006 года пользуюсь сам DokuWiki, накопил более 900 заметок и статей для своих нужд. С тех под много что другого настраивал и пробовал (MediaWiki, BookStack, WikiJS, etc). Но видимо я уже динозавр, так как мне Dokuwiki проще и привычнее. Однако молодежь требует более простых инструментов. Outline действительно прост в использовании, красив и удобен. Еще бы поднимался одной кнопкой и кушал 50 Мб ОЗУ - было бы вообще идеально )))
AlexGluck
А где xwiki в голосовалке?
Dorlas Автор
Движков более 100 видов, я про такой не слышал)))
http://m.traditio.wiki/Список_вики-движков
Dorlas Автор
попробовал xwiki через docker - при входе в WEB-интерфейс начинает отсчет процентов инициализации - на 50% падает.