Как я докатился до жизни такой?

Всех приветствую. Это мой сайт. Сам я FavorPTG и так меня кто-то может знать в интернете. Вообще, это не первая моя статья на ndlink.ru, но только сейчас я решил полноценно представиться, так как это уже полноценная статья – то, ради чего всё это создавалось. А рассказать я хотел о том, что, зачем и почему я делал на пути к независимости в части некоторых интернет-сервисов. Скажу сразу: моей давней мечтой было запустить свою почту. Помимо очевидного плюса, что ваш адрес может быть admin@... (даже не думайте спорить – это неоспоримый плюс, как и RGB-подсветка на ПК 😂😂), это ещё и независимость и возможность более тонкой настройки. Это то, что было важно для меня. Но есть и минусы, о которых я знал с самого начала: вам нужен домен. И если вы где-то регистрируетесь на эту почту, то домен этот должны стать вашим просто на веки! Причина: боты, которые массово скупают просроченные домены, тоже запускают там почту и всё – теперь они могут попытаться восстановить пароль от вашего аккаунта. А вы – нет, домен-то больше не ваш. И это реально большая проблема. Особенно по части ценообразования региональных DNS-провайдеров. Напомню, что цена домена из зон типа .ru часто резко возрастает на второй-третий год продления. Вы купили новый домен (обычно минимум на год) за 300 рублей. А за второй год получаете счёт на 1300. Продлили его ещё на год – цена вырастет снова. И снова. И снова. Не так резко (тут я сильно утрирую) но цена будет расти.

Резюмирую: хотите свою почту – готовьтесь с каждым годом отдавать за домен либо круглую сумму за международный домен, либо всё большое и больше. И обязательно имейте подушку безопасности, чтобы быстро восстановить доступ к аккаунтам, где использовалась ваша почта, если она вдруг станет не вашей.

Зато с остальными сервисами сильно проще! Лично для меня важно было настроить синхронизацию паролей. У меня большое количество устройств и раньше перенос паролей был сущим адом. Основная их часть была на телефоне. То есть для части аккаунтов схема была следующая: взять телефон, подключиться по kde connect к ПК (если этого не произошло автоматически), зайти в менеджер паролей, найти нужный, скопировать его, передать буфер обмена на ПК, вставить пароль в нужное поле. Не то чтобы это сложно, но удобством точно не пахнет. Вот тут и спасает синхронизация. Я не решался доверять пароли сторонним сервисам (и вам не советую), а вот у себя на сервере – другое дело.

Что ещё вам может понадобиться? Кто знает... Мне вот нужен был сервис для синхронизации заметок Obsidian. Я пользовался WebDAV к mail ru drive, а ещё чуть ранее – к Yandex disk. Удобно и работает даже при белых списках (новая норма в РФ...), но Яндекс меня подставил довольно жёстко: в какой-то момент просто стал выдавать ошибку синхронизации с требованием заплатить, чтобы дальше пользоваться. Скорее всего я упёрся в какой-то внутренний лимит на месяц, но об этом нигде не сказано, да и заметок у меня на пару мегабайт. Эх контора...

Но давайте к практике.

Как поднимать сервисы?

Первый вопрос, которым вы можете задаться: как поднимать кучу сервисов на одном VPS? Ответ простой: через docker. Именно так у меня работает большая часть всего. Исключение – этот сайт. Он написан на golang, зависимостей не требует, компилируется в один файл.

Кратко расскажу о docker. Если не планируете создавать что-то своё, то вам нужен docker-compose. Он предельно прост: создаёте файл docker-compose.yaml, заполняете его, а затем выполняете docker compose up -d. И всё. Если сервис настроен верно, то он запустится и будет работать. Если нет – можете проверить это командой docker logs *container_name*. Либо изначально запускать docker-compose без флага -d – в таком случае весь лог будет идти в открытую консоль.

Ниже пример файла docker-compose.yaml для сервиса WebDAV-хранилища файлов:

services:
  webdav:
    image: ionelmc/webdav:latest
    container_name: webdav
    restart: unless-stopped
    ports:
      - "127.0.0.1:8081:8080"
    environment:
      - WEBDAV_USERNAME=admin
      - WEBDAV_PASSWORD=PASSWORD
    volumes:
      - ./data:/var/webdav

Поясню, что тут происходит:

  1. Мы создаём новый сервис webdav и названием контейнера тоже webdav (можно и по разному – это ни на что не влияет).
  2. Используем официальный образ ionelmc/webdav:latest (рекомендую указывать конкретную версию, а не latest, если вам нужна стабильность, однако контейнер не обновляется автоматически, так что если оно работает – оно работать и будет)
  3. Связываем порт 8081 на вашем VPS с портом 8080 в контейнере. Именно на порту 8080 работает webdav.
  4. Связываем локальную директорию ./data (будет создана рядом с файлом docker-compose) с директорией /var/webdav в контейнере.
  5. В блоке environment задаются переменные окружения для контейнера. Они будут отличаться для каждого образа контейнера, так что изучайте документацию. В данном случае это настройки логина и пароля для доступа к хранилищу.
  6. Ну и через restart: unless-stopped мы указываем, что при любом сбое контейнер должен быть перезапущен.

Ничего сложного. Если у вас всё же возникают сложности с самостоятельным описанием контейнера, то знайте, что большинство образов сопровождается примером файла docker-compose.yaml – google вам в помощь. Само собой, я многого не уточнил и у docker много своих особенностей, которые вы можете/должны знать/использовать, но в этой статье я и не имею цели обучить вас работе с docker.

Как создать защищённое соединение?

После запуска вашего сервиса, он будет доступен в браузере по адресу http://*IP вашего сервера:8081. Это уже круто! Но http не безопасен и все данные передаются в открытом виде. Сейчас крайне небольшое количество публичных сервисов используют http. В основном, это те, кто не собирают от пользователей никаких данных, не имеют баз данных и прочего – просто статические страницы, сайты-визитки и подобное.

Нам это не подходит, так что давайте защитим наш сервис от утечек данных! Самый простой способ это сделать – reverse-proxy. Это программа, которая подхватывает запрос, оборачивает его в https и уже в таком виде отправляет пользователю. Безопасно и не сложно.

Однако, перед тем, как настраивать защищённое соединение, нам необходим домен. Только на домен можно получить полноценный SSL-сертификат. Можно использовать и самоподписный на IP, но на него браузер будет ругаться и могут быть проблемы с работой API (если вдруг они у вас есть). В данной статье я не буду рассматривать то, как получить доменное имя. Будем считать, что оно у вас уже есть.

Теперь необходимо получить SSL-сертификаты. Это можно сделать на сайте let's encrypt, либо через программу certbot прямо на сервере.

Воспользуемся вторым вариантом. Если у вас ещё не установлен nginx – установите его, он нам понадобится. А также всё необходимое. Сделать это можно следующей командой на Ubuntu/Debian (для других ОС смотрите команды сами):

sudo apt update && sudo apt install -y nginx certbot python3-certbot-nginx

Nginx должен запуститься в фоне автоматически. Можете проверить это следующей командой:

sudo systemctl status nginx

Если всё в порядке, выполните следующую команду, указав своё доменное имя:

sudo certbot certonly --nginx -d webdav.example.com

Если вы только что изменили параметры домена (например, добавили A запись и хотите использовать её), то certbot может выдать ошибку. В таком случае подождите пару минут – DNS-записи обновятся и команда выполнится без проблем. В результате вы получите путь к созданным файлам сертификатов. Они нам скоро понадобятся.

Далее я буду использовать nginx. Для описания нового сервиса, создайте любой понятный всм файл по пути /etc/nginx/sites-available/*name_of_file* с подобным содержимым:

server {
    listen 80;
    server_name webdav.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name webdav.example.com;

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

    # Максимальный размер загружаемого файла
    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:8081;
        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 $scheme;
    }
}

Что тут происходит:

  1. В первом блоке server мы задаём правило, при котором любой запрос http к нашему WebDAV будет перенаправлен на https.
  2. Во втором блоке мы задаём правила для https: имя сервера, на который придёт запрос, пути к ssl-сертификатам, максимальный размер тела запроса (в основном, не обязательно), а также настройки перенаправления полученного запроса на локальный http.
  3. Собственно, блок location / {...} отвечает за то, какой адрес мы певерс-проксируем.
  4. proxy_pass http://127.0.0.1:8081 заставляет nginx перенаправлять все запросы с https://webdav.example.com/ на локальный http://127.0.0.1:8081/.
  5. proxy_set_header Host $host заставляет nginx передать внутреннему сервису имя хоста, на которое пришёл запрос. В данном случае это webdav.example.com. Без этой строки внутренний сервис будет считать, что запрос пришёл на 127.0.0.1.
  6. proxy_set_header X-Real-IP $remote_addr заставляет nginx передать внутреннему сервису реальный IP-адрес пользователя. Без неё сервис будет считать, что запрос пришёл от самого nginx, а не от пользователя.
  7. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for передаёт внутреннему сервису полную цепочку IP-адресов, которые прошёл запрос. Это нужно в случае, например, использования прокси (от cloudflare или подобрые).
  8. proxy_set_header X-Forwarded-Proto $scheme передаёт внутреннему сервису протокол, по которому реально пришёл запрос. Без него сервис будет считать его http, так как именно так его присылает nginx. Это довольно шаблонная конструкция и её можно дополнительно адаптировать для других сервисов.

Теперь нужно сделать сервис активным, заставить nginx прочитать новую конфигурацию и перезапустить его:

sudo ln -s /etc/nginx/sites-available/webdav /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Готово! Теперь попробуйте зайти на страницу, вписав http://webdav.example.com и увидите, что окажетесь на https://webdav.example.com. Само собой, замените домен на свой.

Более сложные сервисы

Самым сложным, что я настраивал, была почта. Это многоуровневая процедура, связывающая воедино настройку DNS-записей, сервера, а в моём случае ещё и web-клиента.

Думаю, в основном за этим вы сюда и пришли)) Приступим!

Первое, что мы сделаем – это настроим DNS-записи на сервере:

  1. A запись: mail.example.com -> IP_VPS
  2. MX запись: example.com -> значение: mail.example.com (приоритет 10)
  3. TXT запись: v=spf1 mx a ip4:IPVPS ~all
  4. TXT запись: _dmarc.example.com -> значение: v=DMARC1; p=none; rua=mailto:postmaster@example.com

Готово. Остальное не трогаем.

Теперь нужно настроить сам сервер: добавить PTR-запись (Reverse DNS) для вашего IP-адреса на значение mail.example.com. Тут я мало, что могу советовать, так как у разных провайдеров это делается по разному. Чаще всего нужно писать в тех-поддержку и они всё сделают.

Этот этап можно отложить и, наконец, приступить к настройке ПО. Я использовал проект docker-mailserver. На его примере показывать и буду.

Для начала, создадим на сервере новую директорию и скачаем туда всё необходимое:

mkdir -p ~/mailserver && cd ~/mailserver

# Официальный установочный скрипт управления (setup.sh)
curl -sSL https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master/setup.sh -o setup.sh
chmod +x setup.sh

# Пример файла docker-compose.yml
curl -sSL https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master/compose.yaml -o docker-compose.yml

# Переменные окружения для сервера
curl -sSL https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master/mailserver.env -o mailserver.env

Обратите внимание, что переменные окружения вынесены в отдельный файл. Связано это с тем, что их довольно много. Поэтому в docker-compose.yaml нужно поменять только имя хоста на своё (поле OVERRIDE_HOSTNAME=mail.example.com) и добавить:

volumes:
- /etc/letsencrypt/:/etc/letsencrypt/:ro

Сразу сгенерируем сертификаты для сервера. Для этого воспользуемся уже знакомым вам certbot:

sudo certbot certonly --nginx -d mail.example.com

Далее переходим в файл mailserver.env. Файл хорошо документирован, так что можете изучить его и включить/отключить то, что Вам нужно. Из интересного:

# Отключаем тяжелый антивирус
ENABLE_CLAMAV=0
    
# Включаем легкий и умный антиспам
ENABLE_RSPAMD=1

# Защита от подбора паролей
ENABLE_FAIL2BAN=1
  
# SSL-сертификаты
SSL_TYPE=manual
SSL_CERT_PATH=/etc/letsencrypt/live/mail.example.com/fullchain.pem
SSL_KEY_PATH=/etc/letsencrypt/live/mail.example.com/privkey.pem

Теперь запустим docker:

sudo docker compose up -d

Когда он запустится, можем создать нашего первого пользователя, а также алиас на системного пользователя, который будет получать отчёты:

./setup.sh email add admin@example.com
./setup.sh alias add postmaster@example.com admin@example.com

Команда создаст пользователя admin и попросит ввести пароль для него. Не отказываем ей в этом удовольствии.

Теперь сгенерируем цифровую подпись для наших писем:

./setup.sh config dkim

Команда создаст файл, который мы должны прочитать:

cat docker-data/dms/config/opendkim/keys/example.com/mail.txt

Там будет что-то вроде этого:

mail._domainkey IN TXT ( "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQ..." )

Осталось создать ещё одну DNS-запись типа TXT, хост mail._domainkey.example.com, а в качестве значения вставьте содержимое mail.txt (то, что в скобках, но без кавычек).

После всего этого можно попробовать отправить наше первое письмо. Сделать это можно прямо из консоли:

docker exec -it mailserver swaks --to my_best_real_email@gmail.com \
  --from admin@example.com \
  --server localhost:587 \
  --auth LOGIN \
  --auth-user admin@example.com \
  --auth-password "ПАРОЛЬ_ОТ_ADMIN" \
  --header "Subject: Test mail from VPS" \
  --body "Привет! Это первое тестовое письмо."

Зайдите на свою почту и порадуйтесь тому, что увидите письмо со своего собственного домена и скорее всего со сбитой кодировкой из за специфики консоли 😂😂! Не переживайте – всё в норме!

Следующий шаг – открыть почтовый клиент и добавить туда Вашу новую почту точно так же, как вы это делали с mail.ru или подобными.

Готово! Я вас поздравляю с ещё одним шагом к независимости от корпораций! Думаю, это не последняя моя статья по настройке сервера – будет ещё про создание блога, про хранилище паролей vaultwarden, возможно ещё о чём-то.

На этом у меня всё. Найти меня можно:
В matrix: @favorptg:tchncs.de
В telegram: @FavorPTG
В X.com: @MetthewRog52189

Всем мира и удачи!