С российского рынка уже ушли многие ИТ-продукты, которыми мы привыкли пользоваться в рабочих целях. Сложно сказать, какой софт станет недоступен следующим — хочется найти замену заранее, чтобы не остаться без необходимых инструментов. Мы решили потестировать разные продукты и в первую очередь найти альтернативу Confluence или Notion: нужна была удобная база знаний, которая не зависит от внешнего мира и не скажет тебе в один момент «пока». В итоге мы определили интересный вариант, и в этом материале хотим поделиться пошаговой инструкцией по развертыванию стека на собственном сервере.
Всем привет! Меня зовут Игорь, я DevOps в Malov.Tech[ссылка удалена мод.]. Недавно я нашел и развернул open-source wiki-систему для нашей команды, которую мы теперь используем как базу знаний. В статье я расскажу, на что стоит обратить внимание, когда запускаешь решение на собственном сервере. Также записал подробную видео-инструкцию — она доступна выше. Рекомендую и прочитать статью, и посмотреть инструкцию, тогда все точно получится повторить :)
Предыстория
Мы в команде искали сервис, который сможет заменить Confluence и в процессе наткнулись на Outline. Протестировали его какое-то время и поняли, что нас он абсолютно устраивает по функциональности.
Итак, Outline — это open-source база знаний, основанная на markdown-подобном языке, для коллективного пользования. Редактор поддерживает маркдаун и позволяет структурировать информацию с учетом разделения доступов. Мы храним здесь бизнес-требования заказчика, технические задания, ссылки на различные материалы и данные по коллегам (дни рождения и т.д).
Принцип ведения записей
Если TTL (срок годности) информации больше чем несколько дней, то эту инфу стоит структурно занести в Outline.
Все могут в любой момент дополнить и структурировать чужой текст.
Outline ведем все вместе.
Недостатки тоже есть, поскольку решение свежее и, по сути, MVP: нет возможности посмотреть, кто именно редактировал текст, нет баз данных как в Notion, но ребята взяли высокий темп разработки и, уверен, скоро наверстают функционал.
Мы развернули стек на виртуальном сервере с Ubuntu 20.04, 2 ГБ RAM и 2 CPU + на сервере активны еще 2-3 сервиса, необходимых для полноценной работы.
Инструкция
Предполагается, что вы уже установили:
1. Docker — https://docs.docker.com/engine/
2. Portainer — https://docs.portainer.io/start/install/server/docker/linux
Поэтому, начнем сразу из Portainer:
3. Создаем новую сеть докера, которая будет использоваться во всех необходимых сервисах.
- Networks > Add network > называем её: reverseproxy
4. Устанавливаем Nginx-Proxy-Manager (далее NPM, но не путаем его условную аббревиатуру с консольной командой "npm" — менеджера пакетов, входящего в Node.js). Наш NPM - это фактически тот же Nginx, только с интуитивно понятным веб-интерфейсом.
В рамках этого гайда с помощью NPM мы добавим конфигурацию Nginx. В нем мы настроим обратный прокси для подключенных к сети reverseproxy сервисов и получим для наших доменов SSL-сертификаты Let's Encrypt.
- Stacks > Add stack
Пример готового стека:
version: "3"
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
# В формате <host-port>:<container-port>
- '80:80' # Public HTTP Port
- '443:443' # Public HTTPS Port
- '81:81' # Admin Web Port
environment:
DB_MYSQL_HOST: "db"
DB_MYSQL_PORT: 3306
DB_MYSQL_USER: "npm"
DB_MYSQL_PASSWORD: ${MYSQL_PASSWORD}
DB_MYSQL_NAME: "npm"
# true, если IPv6 не включен на вашем хосте
DISABLE_IPV6: 'true'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
depends_on:
- db
networks:
- nginx-proxy-manager
- reverseproxy
db:
image: 'jc21/mariadb-aria:latest'
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: 'npm'
MYSQL_USER: 'npm'
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- ./data/mysql:/var/lib/mysql
networks:
- nginx-proxy-manager
networks:
nginx-proxy-manager:
reverseproxy:
external: true
Ниже нажимаем "Advanced mode", либо два раза "Add an environment variable" >
MYSQL_ROOT_PASSWORD=<сгенерированный пароль, например, через openssl rand -hex 20>
MYSQL_PASSWORD=<сгенерированный пароль, например, через openssl rand -hex 20>
Если установка прошла корректно, вы сможете зайти в веб-панель NPM по адресу http://{ip-адрес-сервера}:81
через стандартный аккаунт админа:
- Логин: admin@example.com
- Пароль: changeme
5. Установим Outline.
Обратите внимание, стандартные порты Outline и MinIO (о MinIO ниже) мы сразу делаем закрытыми (закомментировав), и включаем эти сервисы в сеть "reverseproxy". Немного позже настроим обращение к этим портам через NPM с помощью обратного прокси.
- Stacks > Add stack
Пример готового стека:
version: "2"
services:
outline_redis:
image: redis
restart: always
container_name: outline_redis
networks:
- outline-internal
outline_postgres:
image: postgres:13
restart: always
container_name: outline_postgres
environment:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_USER=outline
- POSTGRES_DB=outline
networks:
- outline-internal
volumes:
- /mnt/containers/outline/container-data/db:/var/lib/postgresql/data:Z
# ports:
# - 5432:5432
outline_minio:
image: minio/minio
restart: always
container_name: outline_minio
volumes:
- /mnt/containers/outline/container-data/data:/data:Z
environment:
- MINIO_ROOT_USER=minio
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
- MINIO_BROWSER_REDIRECT_URL=${MINIO_BROWSER_REDIRECT_URL}
# ports:
# - 9000:9000
# - 9001:9001
networks:
- reverseproxy
command: "server /data --console-address :9001"
outline:
image: outlinewiki/outline
user: root
restart: always
container_name: outline
command: sh -c "yarn sequelize:migrate --env=production-ssl-disabled && yarn start --env=production-ssl-disabled"
depends_on:
- outline_postgres
- outline_redis
- outline_minio
environment:
- PGSSLMODE=disable
- SECRET_KEY=${SECRET_KEY}
- UTILS_SECRET=${UTILS_SECRET}
- DATABASE_URL=postgres://outline:${POSTGRES_PASSWORD}@outline_postgres:5432/outline
- REDIS_URL=redis://outline_redis:6379
- URL=${WIKI_URL}
- PORT=443
- AWS_ACCESS_KEY_ID=minio
- AWS_REGION=us-east-1
- AWS_SECRET_ACCESS_KEY=${MINIO_ROOT_PASSWORD}
- AWS_S3_UPLOAD_BUCKET_URL=${WIKIDATA_URL}
- AWS_S3_UPLOAD_BUCKET_NAME=outline
- AWS_S3_UPLOAD_MAX_SIZE=26214400
- AWS_S3_FORCE_PATH_STYLE=true
- AWS_S3_ACL=private
# При необходимости, можно сразу добавить авторизацию с помощью Slack:
#- SLACK_CLIENT_ID=${SLACK_CLIENT_ID}
#- SLACK_CLIENT_SECRET=${SLACK_CLIENT_SECRET}
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
# ports:
# 443:443
networks:
- outline-internal
- reverseproxy
networks:
outline-internal:
reverseproxy:
external: true
5.1 Добавим environment variables в наш Outline Stack
Disclaimer: для первичной авторизации в Outline мы будем использовать Google OAuth 2.0. Вы можете выбрать, например, Slack. Больше сведений о конфигурации Outline можно посмотреть в файле https://github.com/outline/outline/blob/main/.env.sample
- Environment variables > Advanced mode
❗ Обратите внимание, SECRET_KEY и UTILS_SECRET обязательно должны быть 32-битными паролями.
SECRET_KEY={сгенеруйте пароль, например, командой: openssl rand -hex 32}
UTILS_SECRET={сгенеруйте пароль, например, командой: openssl rand -hex 32}
POSTGRES_PASSWORD={сгенеруйте пароль, например, командой: openssl rand -hex 20}
MINIO_ROOT_PASSWORD={сгенеруйте пароль, например, командой: openssl rand -hex 20}
MINIO_BROWSER_REDIRECT_URL=https://wikidata-admin.{Ваш-домен}
WIKI_URL=https://wiki.{Ваш-домен}
WIKIDATA_URL=https://wikidata.{Ваш-домен}
GOOGLE_CLIENT_ID={Поменять на ваш id из https://console.cloud.google.com/}
GOOGLE_CLIENT_SECRET={Поменять на ваш Client secret из https://console.cloud.google.com/}
5.2 Ваши GOOGLE_CLIENT_ID и GOOGLE_CLIENT_SECRET необходимо получить в личном кабинете Google Cloud https://console.cloud.google.com/
- Создаем проект (если еще не создан) > APIs & Services > Credentials > Create credentials > OAuth Client ID
![](https://habrastorage.org/getpro/habr/upload_files/647/676/869/6476768692aa32b9b3a38cf2a9e847b7.jpeg)
Далее,
- Application type: Web application
- Name: подходящее название вашего client ID
- Authorized JavaScript origins: https://wiki.<Ваш-домен>
- Authorized redirect URIs: https://wiki.<Ваш-домен>/auth/google.callback
![](https://habrastorage.org/getpro/habr/upload_files/320/a31/c05/320a31c05db6dcc20fcda551c58d80d2.jpeg)
6. Настроим обратный прокси через Nginx-Proxy-Manager:
В NPM http://{ip-адрес-сервера}:81
> Hosts > Add host
Для Outline мы будем использовать 3 поддомена, в нашем случае это будут:
wiki.malov.tech - основной адрес
wikidata-admin.malov.tech - для админского веб-интерфейса MinIO
wikidata.malov.tech - технический домен для системы объектного хранения MinIO
6.1 - wiki.malov.tech
![](https://habrastorage.org/getpro/habr/upload_files/d00/5a0/9ed/d005a09ede805469868e25c293342a00.jpeg)
![](https://habrastorage.org/getpro/habr/upload_files/d54/e53/e51/d54e53e5185311a1649e779be941f4f7.jpeg)
6.2 wikidata-admin.malov.tech
![](https://habrastorage.org/getpro/habr/upload_files/102/a08/085/102a080858f6ea07dbf0d74544d5cd76.jpeg)
![](https://habrastorage.org/getpro/habr/upload_files/19b/1bf/67c/19b1bf67c1a89629cd157b719d7d7f6a.jpeg)
6.3 wikidata.malov.tech
![](https://habrastorage.org/getpro/habr/upload_files/a0f/7be/5a7/a0f7be5a73d0f353f403775463aab329.jpeg)
![](https://habrastorage.org/getpro/habr/upload_files/cfd/6f8/5c0/cfd6f85c09a5738ac2c4d4e58fdd9edd.jpeg)
7. Дополнительно можно настроить SMTP для email оповещений из Outline, а также настроить обратный прокси для NPM и Portainer, закрыв прямой доступ к ним по айпи без SSL.
Вместо заключения
На этом все! Вы развернули базу знаний Outline на собственном сервере, и она не покинет вас по личным взглядам инвестора или собственника. Вы сможете складывать сюда все артефакты, которые касаются вашего бизнеса: документы, ссылки, вырезки, скриншоты, алгоритмы — все, что раньше хранилось в Confluence, Notion и Google Docs. Самый большой плюс — исходники всегда у вас под рукой, его можно развернуть и пользоваться. Надеюсь, что у вас тоже сложится положительный опыт использования данной вики-системы.