Apps: "XWiki", "Nginx", "Docker", "Docker Compose", LDAP.
Задача: развернуть в среде исполнения "Docker" написанное на "Java" web-приложение "XWiki", предназначенное для ведения документации и публикации структурированных текстовых данных.
Почему "XWiki"? На протяжении последних пяти лет я активно пользовался "DokuWiki" и "Atlassian Confluence". Первое web-приложение привлекает крайней внутренней простотой, но непривычно для пользователей, избалованных современными ajax-овыми интерфейсами. Второй вариант с точки зрения "usability" на высоте, но стоимость лицензии чрезвычайно велика.
Пришло время пройтись по списку актуальных wiki-приложений и сравнить их возможности. Для таких задач даже специальный web-сервис "WikiMatrix" существует.
Уже на первом этапе изучения было выявлено, что известная всем "MediaWiki" не предоставляет механизмов простого и гарантированного ограничения доступа к документам. Для нас это означает, что применять её в корпоративной среде нежелательно.
Создатели "MediaWiki" рекомендуют как альтернативу использовать "Foswiki", "MoinMoin" или "Confluence". Ранее я отмечал, что последняя сильно платная. Первые две системы хранят данные в "flat-file" с самописным форматом.
В сравнении неплохо смотрелась "PmWiki", давно разрабатываемая и обновлённая в Феврале 2020, но данные тоже в "flat-file", что мне не нравится. Таким образом из всего списка осталась буквально одна "XWiki", которую мы и задействуем.
Последовательность дальнейших действий такова:
1. Подготовка системного окружения (отдельная инструкция);
2. Установка системы контейнеризации "Docker" (отдельная инструкция);
3. Установка сопутствующего ПО и подготовка конфигурации;
4. Установка и настройка СУБД "MySQL";
5. Установка фронтального web-сервера "Nginx";
6. Наладка запуска посредством "Docker Compose" и "Systemd";
7. Первоначальная настройка web-приложения "XWiki";
8. Настройка подключения к внешнему LDAP/AD для аутентификации.
2. Установка системы контейнеризации "Docker" (отдельная инструкция);
3. Установка сопутствующего ПО и подготовка конфигурации;
4. Установка и настройка СУБД "MySQL";
5. Установка фронтального web-сервера "Nginx";
6. Наладка запуска посредством "Docker Compose" и "Systemd";
7. Первоначальная настройка web-приложения "XWiki";
8. Настройка подключения к внешнему LDAP/AD для аутентификации.
Подготовка несущей файловой структуры для приложения "XWiki".
Распределение файлов приложения внутри docker-контейнера оставим разработчикам "XWiki", а конфигурационные файлы, загружаемые пользователями данные и журналы событий вынесем в файловую систему несущей системы:
# mkdir -p /var/opt/xwiki/data
# mkdir -p /var/opt/xwiki/log/tomcat
# mkdir -p /var/opt/xwiki/log/tomcat
Создание пользователей и условий для усечения привилегий приложения "XWiki".
Надо отметить, что docker-контейнер для "XWiki" собран ужасно. Любопытно, что творилось в головах тех, кто накручивал все эти костыли в скриптах инициализации. Одним из следствий стало то, что приложение запускается в контексте суперпользователя и без основательной переделки контейнера этого не изменить. На перспективу я завёл выделенных пользователя и группу "xwiki" и передал им во владение файловые ресурсы приложения, но пока это бессмысленно:
# groupadd --system xwiki
# useradd --system --home-dir /var/opt/xwiki --shell /bin/false --gid xwiki xwiki
# useradd --system --home-dir /var/opt/xwiki --shell /bin/false --gid xwiki xwiki
Передаём директории файловых ресурсов приложения выделенному для этого пользователю:
# chown -R xwiki:xwiki /var/opt/xwiki
# chmod -R go-rwx /var/opt/xwiki
# chmod -R go-rwx /var/opt/xwiki
Установка и настройка СУБД "MySQL".
Развёртываемая "XWiki" работает с "базой данных" через прослойку абстракции JDBC, так что теоретически большинство известных реляционных СУБД поддерживаются. Гарантируется работа с "Oracle", "PostgreSQL" и "MySQL". На "энтерпрайз" у нас нет денег, "слона" в последнее время у меня многовато, и для "wiki" мне захотелось простоты - так что ставим "MySQL":
# apt-get install --no-install-recommends mysql-server
Ничего особого в конфигурации СУБД вносить не требуется - лишь немного опций оптимизации "InnoDB" и разрешение подключений отовсюду, чтобы обеспечить возможность соединений из docker-контейнера:
# vi /etc/mysql/mysql.conf.d/mysql.cnf
....
[mysqld]
....
# Разрешаем подключаться отовсюду
bind-address = 0.0.0.0
....
# Выносим временные файлы в удобное нам место
tmpdir = /var/lib/mysql/tmp
innodb_tmpdir = /var/lib/mysql/tmp
....
# Увеличиваем лимит размера временной таблицы, обрабатываемой в ОЗУ, до сброса её в файловую систему
tmp_table_size = 512M
....
# Увеличиваем лимит размера создаваемых пользователем MEMORY-таблицы, обрабатываемой в ОЗУ
max_heap_table_size = 512M
....
# Увеличиваем размер буфера запросов и журнала транзакций
innodb_buffer_pool_size = 2G # (default: 128MB; optimal: 60% RAM)
innodb_log_file_size = 512M # (default: 5MB)
innodb_log_buffer_size = 256M # (default: 8MB)
....
# Указываем записывать журнал транзакций примерно один раз в секунду, а не немедленно после каждого изменения данных (default: 1)
innodb_flush_log_at_trx_commit = 2
....
# Включаем поддержку нового формата файлов InnoDB и длинных индексных ключей
innodb_file_format = barracuda
innodb_large_prefix = 1
# Явно указываем создавать для каждой таблицы отдельные файлы описаний (.frm) и данных (.ibd) на диске, а не сваливать всё в один (ibdataX)
innodb_file_per_table = 1
....
[mysqld]
....
# Разрешаем подключаться отовсюду
bind-address = 0.0.0.0
....
# Выносим временные файлы в удобное нам место
tmpdir = /var/lib/mysql/tmp
innodb_tmpdir = /var/lib/mysql/tmp
....
# Увеличиваем лимит размера временной таблицы, обрабатываемой в ОЗУ, до сброса её в файловую систему
tmp_table_size = 512M
....
# Увеличиваем лимит размера создаваемых пользователем MEMORY-таблицы, обрабатываемой в ОЗУ
max_heap_table_size = 512M
....
# Увеличиваем размер буфера запросов и журнала транзакций
innodb_buffer_pool_size = 2G # (default: 128MB; optimal: 60% RAM)
innodb_log_file_size = 512M # (default: 5MB)
innodb_log_buffer_size = 256M # (default: 8MB)
....
# Указываем записывать журнал транзакций примерно один раз в секунду, а не немедленно после каждого изменения данных (default: 1)
innodb_flush_log_at_trx_commit = 2
....
# Включаем поддержку нового формата файлов InnoDB и длинных индексных ключей
innodb_file_format = barracuda
innodb_large_prefix = 1
# Явно указываем создавать для каждой таблицы отдельные файлы описаний (.frm) и данных (.ibd) на диске, а не сваливать всё в один (ibdataX)
innodb_file_per_table = 1
....
Проверяем синтаксическую корректность конфигурации и применяем её перезагрузкой сервиса:
# mysqld --verbose --help 1>/dev/null
# /etc/init.d/mysql restart
# /etc/init.d/mysql restart
Оптимизация работы "MySQL" с дисковой подсистемой.
Для СУБД, активно создающей и уничтожающей файлы временных таблиц, выгодно вынести (параметром "tmpdir") эту работу в файловую систему, смонтированную в область памяти ОЗУ:
# mkdir -p -m 750 /var/lib/mysql/tmp
# chown -R mysql:mysql /var/lib/mysql/tmp
# chown -R mysql:mysql /var/lib/mysql/tmp
# vi /etc/fstab
....
# Tuning the location of MySQL temporary files
tmpfs /var/lib/mysql/tmp tmpfs rw,nosuid,nodev,size=2G,uid=mysql,gid=mysql,mode=0750 0 0
....
# Tuning the location of MySQL temporary files
tmpfs /var/lib/mysql/tmp tmpfs rw,nosuid,nodev,size=2G,uid=mysql,gid=mysql,mode=0750 0 0
....
# mount /var/lib/mysql/tmp
Я выделяю под эту файловую систему до 20% от всей ОЗУ (она не заблокирует весь заявленный объём, а будет выбирать блоки памяти по мере появления необходимости).
Ограничение сетевого доступа к СУБД извне несущего сервера.
В конфигурации выше мы были вынуждены разрешить сетевые подключения к СУБД отовсюду, чтобы обеспечить простой провод трафика из docker-контейнера, запущенного рядом. Нам достаточно, чтобы сервис "MySQL" был доступен на уровне несущего сервера, так что будет полезным запретить подключения извне совсем:
# iptables -t filter -L INPUT -n -v --line-numbers
# iptables -A INPUT -i eth0 -p TCP --dport 3306 -j REJECT -m comment --comment "Forbidding external connections to MySQL"
# iptables -A INPUT -i eth0 -p TCP --dport 3306 -j REJECT -m comment --comment "Forbidding external connections to MySQL"
Для сохранения правил защитного экрана и активации их при запуске операционной системы применим специализированную утилиту:
# aptitude install iptables-persistent
# netfilter-persistent save
# netfilter-persistent save
Создаём пользователя и регистрируем "базу данных" для "XWiki".
Всё просто, отдаём команды создания БД, пользователя и наделения последнего неограниченными полномочиями доступа к выделенной "баз данных", в соответствии с рекомендациями разработчиков:
# mysql
MySQL> DROP DATABASE `xwiki`;
MySQL> CREATE DATABASE `xwiki` CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
MySQL> CREATE USER 'xwiki'@'%' IDENTIFIED BY 'xwiki_db_password';
MySQL> GRANT ALL PRIVILEGES ON xwiki.* TO 'xwiki'@'%';
MySQL> FLUSH PRIVILEGES;
MySQL> QUIT;
MySQL> DROP DATABASE `xwiki`;
MySQL> CREATE DATABASE `xwiki` CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
MySQL> CREATE USER 'xwiki'@'%' IDENTIFIED BY 'xwiki_db_password';
MySQL> GRANT ALL PRIVILEGES ON xwiki.* TO 'xwiki'@'%';
MySQL> FLUSH PRIVILEGES;
MySQL> QUIT;
Установка фронтального web-сервера "Nginx".
В развёртываемое приложение встроен web-сервер "Tomcat". Однако на практике для приёма и первичной обработки клиентских подключений удобнее использовать более легковесный web-сервер. Воспользуемся "Nginx":
# aptitude install nginx-light
Для последующего включения в "Nginx" современного SSL/TLS и HTTPv2 генерируем DH-файл:
# mkdir -p /etc/ssl/nginx && chown -R root:root /etc/ssl/nginx
# openssl dhparam -out /etc/ssl/nginx/dhparam.2048.pem 2048
# openssl dhparam -out /etc/ssl/nginx/dhparam.2048.pem 2048
Слегка преднастроим web-сервер:
# vi /etc/nginx/nginx.conf
user www-data www-data;
worker_processes auto;
....
http {
....
server_tokens off;
client_max_body_size 0;
....
worker_processes auto;
....
http {
....
server_tokens off;
client_max_body_size 0;
....
Конфигурация принимающего подключения пользователей web-сервера "Nginx" проста и сводится к описанию параметров "проксирования" всех запросов нижележащему web-сервису, запущенному внутри docker-контейнера:
# vi /etc/nginx/sites-available/xwiki.example.net.conf
server {
listen 80;
server_name xwiki.example.net;
location / { rewrite ^(.+)$ https://$host$1 permanent; }
#include /etc/nginx/snippets/letsencrypt.conf;
}
server {
listen 443 ssl http2;
server_name xwiki.example.net;
access_log /var/log/nginx/xwiki.example.net_access.log;
error_log /var/log/nginx/xwiki.example.net_error.log;
ssl_dhparam /etc/ssl/nginx/dhparam.2048.pem;
ssl_certificate /etc/ssl/nginx/wildcard.example.net.crt;
ssl_certificate_key /etc/ssl/nginx/wildcard.example.net.key.decrypt;
ssl_protocols SSLv2 SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme https;
proxy_set_header X-Forwarded-Proto https;
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-NginX-Proxy true;
# (HTTPv1.1 & WebSocket)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 240;
proxy_send_timeout 240;
proxy_read_timeout 240;
}
}
listen 80;
server_name xwiki.example.net;
location / { rewrite ^(.+)$ https://$host$1 permanent; }
#include /etc/nginx/snippets/letsencrypt.conf;
}
server {
listen 443 ssl http2;
server_name xwiki.example.net;
access_log /var/log/nginx/xwiki.example.net_access.log;
error_log /var/log/nginx/xwiki.example.net_error.log;
ssl_dhparam /etc/ssl/nginx/dhparam.2048.pem;
ssl_certificate /etc/ssl/nginx/wildcard.example.net.crt;
ssl_certificate_key /etc/ssl/nginx/wildcard.example.net.key.decrypt;
ssl_protocols SSLv2 SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme https;
proxy_set_header X-Forwarded-Proto https;
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-NginX-Proxy true;
# (HTTPv1.1 & WebSocket)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 240;
proxy_send_timeout 240;
proxy_read_timeout 240;
}
}
Удаляем конфигурацию "по умолчанию", активируем новую, проверяем и запускаем в работу:
# rm /etc/nginx/sites-enabled/default
# ln -s /etc/nginx/sites-available/xwiki.example.net.conf /etc/nginx/sites-enabled/xwiki.example.net.conf
# nginx -t && nginx -s reload
# ln -s /etc/nginx/sites-available/xwiki.example.net.conf /etc/nginx/sites-enabled/xwiki.example.net.conf
# nginx -t && nginx -s reload
Об установке web-приложения "XWiki".
Команда разработчиков сама собирает docker-контейнер с "XWiki" и публикует их на общеизвестном сервисе "Docker Hub" в соответствующем разделе https://hub.docker.com/_/xwiki/. Не вижу причин не воспользоваться этим, хотя качество скриптов конфигурации и ужасающе (просто будем надеяться, что это со временем будет исправлено). Некоторые аспекты конфигурирования docker-контейнеров "XWiki" описываются в документации, прикреплённой к исходному коду в git-репозитории проекта на "github.com".
В наличии несколько вариантов сборок: "latest", "stable" и "lts". Для долгоиграющих корпоративных сервисов лучше выбирать последнюю.
(опционально) Адаптация "Tomcat" для работы в спарке с "Nginx".
На практике выяснилось, что в этом нет необходимости - по умолчанию "XWiki" настроен так, что исходящие перенаправления осуществляет с относительным путём (без указания протокола и доменного имени).
С учётом того, что запросы пользователей принимаются web-сервером "Nginx", а обрабатываются скрытым за ним "Tomcat", желательно согласовать адреса FQDN и номера сетевых портов терминирования, которые должны сохранятся неизменными на протяжении всей цепочки обработки запроса, при передачи от сервера к серверу.
В самом простом случае достаточно уведомить web-сервис "Tomcat" о параметрах терминирования клиентских запросов вышестоящим проксирующим web-сервисом, чтобы в ответах таковому вместо внутренних имени сайта "localhost", порта "8080" и протокола "http" было указано то, что видится клиентам снаружи. Для этого достаточно модифицировать всего одну секцию в XML-файле конфигурации "Tomcat". В нашем случае этот конфигурационный файл внутри docker-образа, что несколько осложняет дело.
Предварительно добываем дистрибутивный файл конфигурации из docker-образа:
# docker create --name tmp-xwiki xwiki:lts-mysql-tomcat
# docker cp tmp-xwiki:/usr/local/tomcat/conf/* /var/opt/xwiki/conf/tomcat
# docker rm tmp-xwiki
# docker cp tmp-xwiki:/usr/local/tomcat/conf/* /var/opt/xwiki/conf/tomcat
# docker rm tmp-xwiki
Вносим необходимые изменения:
# vi /var/opt/xwiki/tomcat/conf/server.xml
<Server ... >
....
<Service name="Catalina">
....
<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
enableLookups="false"
URIEncoding="UTF-8"
<!-- Невостребованный в нашей схеме обслуживания SSL/TLS вышестоящим Nginx параметр редиректа для обслуживания HTTPS-запросов. -->
<!-- redirectPort="8443" -->
<!-- Дополнительный набор параметров описания точки терминирования клиентских запросов вышестоящим проксирующим web-сервисом. -->
proxyName="xwiki.example.net" proxyPort="443" scheme="https"
/>
....
....
<Service name="Catalina">
....
<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
enableLookups="false"
URIEncoding="UTF-8"
<!-- Невостребованный в нашей схеме обслуживания SSL/TLS вышестоящим Nginx параметр редиректа для обслуживания HTTPS-запросов. -->
<!-- redirectPort="8443" -->
<!-- Дополнительный набор параметров описания точки терминирования клиентских запросов вышестоящим проксирующим web-сервисом. -->
proxyName="xwiki.example.net" proxyPort="443" scheme="https"
/>
....
Очевидно, что файлы конфигурации директории "/var/opt/xwiki/tomcat/conf/" впоследствии нужно будет подать внутрь docker-контейнера, запускаемого с web-сервисом "XWiki".
Наладка запуска посредством "Docker Compose".
Создаём директорию для размещения конфигурационных файлов "Docker Compose":
# mkdir /usr/local/etc/compose
# cd /usr/local/etc/compose
# cd /usr/local/etc/compose
Воспользуемся для единственного в нашей схеме конфигурационного файла именем "по умолчанию":
# vi ./docker-compose.yml
version: "3"
services:
xwiki:
container_name: "xwiki-web"
image: "xwiki:lts-mysql-tomcat"
networks:
xwiki:
aliases:
- "xwiki"
ports:
- "127.0.0.1:8080:8080"
environment:
JAVA_OPTS: "-Xms2G -Xmx4G -Dfile.encoding=utf-8 -Djava.awt.headless=true -XX:+UseConcMarkSweepGC -XX:+UseNUMA -XX:+UseCompressedOops"
XWIKI_VERSION: "xwiki"
DB_HOST: "10.20.30.40"
DB_USER: "xwiki"
DB_PASSWORD: "xwiki_db_password"
#INDEX_HOST: "localhost"
working_dir: "/var/opt/xwiki"
volumes:
- "/etc/localtime:/etc/localtime:ro"
- "/etc/timezone:/etc/timezone:ro"
- "/var/opt/xwiki/data:/usr/local/xwiki/data:rw"
- "/var/opt/xwiki/log/tomcat:/usr/local/tomcat/logs:rw"
tmpfs:
- /tmp
- /usr/local/tomcat/temp
- /usr/local/tomcat/work/Catalina/localhost/ROOT/xwiki-temp
networks:
xwiki:
driver: bridge
internal: false
ipam:
driver: default
config:
- subnet: 100.127.255.0/24
services:
xwiki:
container_name: "xwiki-web"
image: "xwiki:lts-mysql-tomcat"
networks:
xwiki:
aliases:
- "xwiki"
ports:
- "127.0.0.1:8080:8080"
environment:
JAVA_OPTS: "-Xms2G -Xmx4G -Dfile.encoding=utf-8 -Djava.awt.headless=true -XX:+UseConcMarkSweepGC -XX:+UseNUMA -XX:+UseCompressedOops"
XWIKI_VERSION: "xwiki"
DB_HOST: "10.20.30.40"
DB_USER: "xwiki"
DB_PASSWORD: "xwiki_db_password"
#INDEX_HOST: "localhost"
working_dir: "/var/opt/xwiki"
volumes:
- "/etc/localtime:/etc/localtime:ro"
- "/etc/timezone:/etc/timezone:ro"
- "/var/opt/xwiki/data:/usr/local/xwiki/data:rw"
- "/var/opt/xwiki/log/tomcat:/usr/local/tomcat/logs:rw"
tmpfs:
- /tmp
- /usr/local/tomcat/temp
- /usr/local/tomcat/work/Catalina/localhost/ROOT/xwiki-temp
networks:
xwiki:
driver: bridge
internal: false
ipam:
driver: default
config:
- subnet: 100.127.255.0/24
Запускаем контейнер, указывая явно имя конфигурационного файла:
# docker-compose up --remove-orphans --build --force-recreate -d
Останавливаем docker-контейнер, описанный в конфигурации "Docker Compose":
# docker-compose down
Настройка автозагрузки "Docker Compose" посредством "Systemd".
Создаём файл описания параметров запуска и остановки docker-контейнера с "XWiki" посредством "Docker Compose" в роли короткоживущего сервиса "Systemd":
# vi /etc/systemd/system/xwiki-docker.service
[Unit]
Description=XWiki in Docker Compose Service
Requires=network.target docker.service containerd.service
After=docker.service mysql.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/usr/local/etc/compose
ExecStartPre=-/bin/bash -c 'chown -R xwiki:xwiki /var/opt/xwiki'
ExecStartPre=/usr/local/bin/docker-compose -f docker-compose.yml down --remove-orphans
ExecStart=/usr/local/bin/docker-compose -f /usr/local/etc/compose/docker-compose.yml up --remove-orphans --build --force-recreate --detach
#
ExecStop=/usr/local/bin/docker-compose -f /usr/local/etc/compose/docker-compose.yml down
[Install]
WantedBy=multi-user.target
Description=XWiki in Docker Compose Service
Requires=network.target docker.service containerd.service
After=docker.service mysql.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/usr/local/etc/compose
ExecStartPre=-/bin/bash -c 'chown -R xwiki:xwiki /var/opt/xwiki'
ExecStartPre=/usr/local/bin/docker-compose -f docker-compose.yml down --remove-orphans
ExecStart=/usr/local/bin/docker-compose -f /usr/local/etc/compose/docker-compose.yml up --remove-orphans --build --force-recreate --detach
#
ExecStop=/usr/local/bin/docker-compose -f /usr/local/etc/compose/docker-compose.yml down
[Install]
WantedBy=multi-user.target
Указываем "Systemd" перечитать и принять новую конфигурацию, а также явно активируем и запускаем новый сервис:
# systemctl daemon-reload
# systemctl enable xwiki-docker.service
# systemctl start xwiki-docker
# systemctl enable xwiki-docker.service
# systemctl start xwiki-docker
Смотрим журнал событий "Systemd" если "что-то пошло не так":
# systemctl status xwiki-docker.service
# journalctl -xe
# journalctl -xe
Первоначальная настройка web-приложения "XWiki".
После всех вышеописанных этапов подготовки окружения можно приступать к настройке "XWiki" посредством его web-интерфейса.
На первом этапе потребуется задать логин и пароль для администратора развёртываемого web-сервиса, а также определиться с набором предустанавливаемых компонентов.
"XWiki" сложная, многокомпонентная система, и её настройка "с нуля" может занять массу времени. Гораздо эффективнее воспользоваться заготовленным разработчиками набором конфигураций, называемым "Flavor" - в нашем случае следует установить "XWiki Standard Flavor".
В составе выбранного (безальтернативно, впрочем) flavor-а будет установлено несколько десятков расширений, практически ненужную часть из которые можно удалить при первом входе в уже готовую к работе систему:
Global Administration -> Extensions:
XWiki Platform - Annotations - UI;
Help Application;
Help Center Application;
XWiki Platform - Invitation - UI;
App Within Minutes Application;
Dashboard Application;
Tour Application;
Menu Application;
Wiki Application;
Application Index Application;
User Directory Application.
Uninstall from farm -> Uninstall -> Continue.
XWiki Platform - Annotations - UI;
Help Application;
Help Center Application;
XWiki Platform - Invitation - UI;
App Within Minutes Application;
Dashboard Application;
Tour Application;
Menu Application;
Wiki Application;
Application Index Application;
User Directory Application.
Uninstall from farm -> Uninstall -> Continue.
Сложность "XWiki" отчасти компенсируется богатством возможностей её настройки, детально описываемых в разделе "Configuration" документации проекта.
Также "XWiki" хорошо поддаётся оптимизации, расписанной в выделенном для этого разделе "Performances" на сайте разработчиков.
Заменяем логотип "XWiki" произвольным.
У предприятия "не одного дня" наверняка имеется свой корпоративный стиль. Естественно, нам захочется как-то применить его к внедряемому web-сервису. В "XWiki" встроены возможности создания новых шаблонов отображения, а также модификации имеющихся. Например, так заменяется дистрибутивный логотип на любое другое изображение:
Global Administration -> Look & Feel -> Themes -> Color Theme -> Customize:
Logos:
@logo -> Choose an attachment -> Upload and select.
Logos:
@logo -> Choose an attachment -> Upload and select.
Настраиваем интеграцию с потовым сервисом.
Для уведомлений пользователей о событиях, а также отслеживания изменений в документах, обязательно настраиваем связь с почтовым сервисом:
Global Administration -> Mail Sending:
EMAIL ADDRESS TO SEND FROM: xwiki@example.net
EMAIL SERVER: mail.example.net
EMAIL SERVER PORT: 25
EMAIL SERVER USERNAME: xwiki@example.net
EMAIL SERVER PASSWORD: xwiki_mail_password
ADDITIONAL PROPERTIES: mail.smtp.starttls.enable=true
EMAIL ADDRESS TO SEND FROM: xwiki@example.net
EMAIL SERVER: mail.example.net
EMAIL SERVER PORT: 25
EMAIL SERVER USERNAME: xwiki@example.net
EMAIL SERVER PASSWORD: xwiki_mail_password
ADDITIONAL PROPERTIES: mail.smtp.starttls.enable=true
На любой существующей странице "XWiki" проверяем возможность отправки почтового уведомления:
Home -> More Actions -> Share by email:
SEND TO: test@example.net
Send.
SEND TO: test@example.net
Send.
Настройка подключения к внешнему LDAP/AD для аутентификации.
Для интеграции с LDAP/AD в "XWiki" используется плагин (или расширение, как его принято здесь называть) "LDAP Authenticator". Устанавливаем его:
Global Administration -> Extensions:
LDAP Authenticator:
Install on farm -> Continue.
LDAP Authenticator:
Install on farm -> Continue.
Полная настройка аутентификации посредством LDAP в "XWiki" через web-интерфейс невозможна - вначале придётся задать как минимум три параметра в основном конфигурационном файле - ну, а раз так, то и всё остальное сделаем так же. Кроме того, при тестировании выяснилось, что предназначенное для настройки через web-интерфейс расширение "LDAP Application" не считывает фактическую конфигурацию из основого файла "xwiki.cfg", что странно - не особо разбираясь в сути проблемы, я предпочёл обойтись без него.
Редактируем основной конфигурационный файл "XWiki":
# vi /var/opt/xwiki/data/xwiki.cfg
....
#-# The authentication management class.
# xwiki.authentication.authclass=com.xpn.xwiki.user.impl.xwiki.XWikiAuthServiceImpl
#-# The authentication management LDAP class.
xwiki.authentication.authclass=org.xwiki.contrib.ldap.XWikiLDAPAuthServiceImpl
#-# Turn LDAP authentication on
xwiki.authentication.ldap=1
#-# Enable local accounts in addition to LDAP.
xwiki.authentication.ldap.trylocal=1
#-# LDAP Server connection
xwiki.authentication.ldap.server=ldap0.example.net
xwiki.authentication.ldap.port=636
xwiki.authentication.ldap.ssl=1
#xwiki.authentication.ldap.ssl.keystore=
#-# LDAP credentials, empty = anonymous access, otherwise specify full dn
#-# {0} is replaced with the user name, {1} with the password
xwiki.authentication.ldap.bind_DN=uid=xwiki,ou=Accounts,ou=Services,dc=example,dc=net
xwiki.authentication.ldap.bind_pass=xwiki_ldap_password
#-# The Base DN used in LDAP searches
xwiki.authentication.ldap.base_DN=dc=example,dc=net
#-# LDAP query to search the user in the LDAP database
#-# {0} is replaced with the user uid field name and {1} with the user name
xwiki.authentication.ldap.user_search_fmt=(&(uid={1})(objectclass=person)(memberOf=cn=xwikiusers,ou=groups,dc=example,dc=net))
#-# Specifies the LDAP attribute containing the identifier to be used as the XWiki name
# xwiki.authentication.ldap.UID_attr=uid
#-# Retrieve the following fields from LDAP and store them in the XWiki user object
xwiki.authentication.ldap.fields_mapping=last_name=sn,first_name=givenName,email=mail,phone=telephoneNumber
#-# On every authentication update the mapped attributes from LDAP to XWiki otherwise this happens only once when the XWiki
xwiki.authentication.ldap.update_user=1
....
#-# The authentication management class.
# xwiki.authentication.authclass=com.xpn.xwiki.user.impl.xwiki.XWikiAuthServiceImpl
#-# The authentication management LDAP class.
xwiki.authentication.authclass=org.xwiki.contrib.ldap.XWikiLDAPAuthServiceImpl
#-# Turn LDAP authentication on
xwiki.authentication.ldap=1
#-# Enable local accounts in addition to LDAP.
xwiki.authentication.ldap.trylocal=1
#-# LDAP Server connection
xwiki.authentication.ldap.server=ldap0.example.net
xwiki.authentication.ldap.port=636
xwiki.authentication.ldap.ssl=1
#xwiki.authentication.ldap.ssl.keystore=
#-# LDAP credentials, empty = anonymous access, otherwise specify full dn
#-# {0} is replaced with the user name, {1} with the password
xwiki.authentication.ldap.bind_DN=uid=xwiki,ou=Accounts,ou=Services,dc=example,dc=net
xwiki.authentication.ldap.bind_pass=xwiki_ldap_password
#-# The Base DN used in LDAP searches
xwiki.authentication.ldap.base_DN=dc=example,dc=net
#-# LDAP query to search the user in the LDAP database
#-# {0} is replaced with the user uid field name and {1} with the user name
xwiki.authentication.ldap.user_search_fmt=(&(uid={1})(objectclass=person)(memberOf=cn=xwikiusers,ou=groups,dc=example,dc=net))
#-# Specifies the LDAP attribute containing the identifier to be used as the XWiki name
# xwiki.authentication.ldap.UID_attr=uid
#-# Retrieve the following fields from LDAP and store them in the XWiki user object
xwiki.authentication.ldap.fields_mapping=last_name=sn,first_name=givenName,email=mail,phone=telephoneNumber
#-# On every authentication update the mapped attributes from LDAP to XWiki otherwise this happens only once when the XWiki
xwiki.authentication.ldap.update_user=1
....
Для активации новой подсистемы аутентификации придётся перезапустить docker-контейнер с web-сервисом:
# systemctl stop xwiki-docker && systemctl start xwiki-docker
Обращаю внимание, что опцией "xwiki.authentication.ldap.trylocal" в конфигурации выше мы обеспечили поддержку аутентификации как через локальную "базу данных" (вроде созданного на этапе развёртывания web-сервиса пользователя "admin"), так и через внешний сервис LDAP/AD. Это удобно: в обыденной работе можно аутентифицироваться через LDAP, а в случае сбоя связи с таковым остаётся возможность залогиниться без применения LDAP.
При настройке интеграции с LDAP-сервисом, трафик которого шифруется "самоподписанным" SSL-сертификатом, соединение не получится установить без дополнительных процедур установления доверительных отношений. Реализация "Java" для "Linux" не позволяет запросто отключить проверку валидности SSL-сертификата. Но отлично работает добавление условно корневого сертификата в общий перечень доверенных, размещаемый обычно в файле "$JAVA_HOME/jre/lib/security/cacerts". Ранее я неоднократно рассказывал, как это делается.