Обратный прокси Traefik: единая точка входа в домашнюю инфраструктуру
Архитектура
Мой домашний сервер, построен на базе Proxmox. Proxmox - это гипервизор с открытым исходным кодом. Благодаря ему, можно через Web-интерфейс управлять контейнерами и вирутальными машинами.
У себя в Proxmox я создал отдельный LXC-контейнер для обратного прокси Traefik, а также отдельные виртуальные машины с уже, непосредственно, моими сервисами. Таким образом LXC-контейнер с Traefik - это, своего рода, точка входа на мой домашний сервер. Именно он принимает все входящие запросы, "фильтрует" их, и дальше направляет на нужную виртуальную машину. Кроме самого Traefik, на нем установлен еще и WireGuard, - как раз чтобы мы могли принимать входящие запросы через мой внешний VPS.
Таким образом, при любом запросе, который не соответствуют разрешенным (не имеют нужного маршрута в настройках Traefik), вернётся просто ошибка 404.
Если такой отдельный LXC-контейнер для обратного прокси - это не более безопасно, то я все-же считаю, что это как минимум удобно и архитектурно чище.
Note
В целом, Traefik можно было бы установить на внешнем VPS, через который осуществляется доступ к моему домашнему серверу из интернета, и фильтровать некорректные запросы и "интернет-шум" уже на его уровне, не пропуская лишний трафик в мою домашнюю сеть. Однако внутри локальной сети я также обращаюсь к сервисам по доменным именам, используя собственный локальный DNS. Поэтому обратный прокси необходим и внутри локальной инфраструктуры. Если бы Traefik работал только на VPS, весь трафик — даже при обращении из локальной сети — проходил бы через интернет, что создаёт лишний маршрут и ненужную зависимость от внешнего канала. Размещая Traefik в LXC-контейнере Proxmox, я получаю единый способ доступа к сервисам по доменным именам как из локальной сети, так и извне. Разница лишь в маршрутизации: внутри сети запросы направляются напрямую на локальные IP-адреса, без выхода в интернет.
Пример маршрута к сервису
Подытожим, что происходит, когда я ввожу в адресной строке браузера, например, https://immich.kvasok.xyz/, находясь вне локальной сети.
DNS-серверы резолвят домен и возвращают IP-адрес моего внешнего VPS. Запрос по HTTPS (порт 443) поступает на VPS, который принимает его и перенаправляет через WireGuard-туннель в сторону моего домашнего сервера. WireGuard-туннель соединён с LXC-контейнером в Proxmox, где запущен обратный прокси Traefik. Traefik принимает входящий запрос, применяет настроенные правила (маршруты, фильтры, middlewares) и, в зависимости от запрошенного поддомена, направляет трафик к соответствующему сервису в моей внутренней сети.
В рассматриваемом примере сервис Immich работает на виртуальной машине с IP-адресом 192.168.1.20 и слушает порт 2283. Соответственно, Traefik проксирует запрос именно на этот адрес и порт, после чего ответ возвращается клиенту по тому же маршруту в обратном направлении.
С помощью ИИ сгенерировал картинку для визуального восприятия:

Структура файлов и каталогов Traefik
Traefik представляет собой единый исполняемый бинарник, который запускается через systemd (или другой init-менеджер) и использует статическую (entryPoints, providers, certificatesResolvers, logs) и динамическую (routers, services, middlewares) конфигурацию.
Моя структура файлов и каталогов для Traefik выглядит следующим образом:
/usr/local/bin/traefik # Исполняемый файл самого Traefik
/etc/systemd/system/traefik.service # systemd unit для Traefik
/etc/traefik/
├── certs/
│ ├── default.crt # Файл SSL-сертификата, который используется по умолчанию
│ └── default.key # Приватный ключ для SSL-сертификата
│
├── dynamic/ # Каталог с файлами динамической конфигурации (routers, services, middlewares)
│ ├── config.yaml # Общая динамическая конфигурация для всех сервисов
│ ├── immich.yaml # Immich
│ ├── nextcloud.yaml # Nextcloud
│ ├── traefik.yaml # Traefik dashboard
│ └── ...
│
├── .env # Переменные окружения (tokens, domains, emails)
├── acme.json # Хранилище Let's Encrypt сертификатов
└── traefik.yaml # Файл статической конфигурации (entryPoints, providers, certificatesResolvers, logs)
Основное в конфигурации это traefik.yaml - файл статической конфигурации, и каталог dynamic - где находятся файлы динамической конфигурации. А также файл acme.json который хранит в себе Let's Encrypt сертификаты. Файл acme.json должен существовать и иметь права доступа 600, иначе Let's Encrypt не будет работать:
chmod 600 /etc/traefik/acme.json
Установка обратного прокси Traefik
Обратный прокси Traefik можно установить как в Docker, так и через бинарный файл. Я у себя установил через бинарник. LXC-контейнер, который я использую, по сути и создавался как точка входа в Traefik, поэтому городить Docker и разводить контейнеризацию как по мне - лишнее.
Заходим по SSH в наш подготовленный LXC-контейнер и качаем бинарник. Последний релиз можно взять отсюда: https://github.com/traefik/traefik/releases. Я подключаюсь к LXC-контейнеру под пользователем root, таким образом мне не нужно у некоторых команд, которые требуют права суперпользователя, писать sudo.
На момент написания статьи используется версия 3.6.8. Создаем папку, качаем архив и распаковываем его в эту папку:
mkdir ./traefik
wget https://github.com/traefik/traefik/releases/download/v3.6.8/traefik_v3.6.8_linux_amd64.tar.gz
tar -zxvf traefik_v3.6.8_linux_amd64.tar.gz -C ./traefik
Далее перемещаем, собственно, сам бинарник Traefik в директорию /usr/local/bin/:
mv ./traefik/traefik /usr/local/bin
Теперь нам нужно создать systemd сервис, который будет автоматически запускать Traefik в нашем LXC-контейнере.
Для этого создаем файл /etc/systemd/system/traefik.service и открываем для редактирования:
touch /etc/systemd/system/traefik.service
nano /etc/systemd/system/traefik.service
Вставляем туда следующее:
[Unit]
Description=Traefik Reverse Proxy
Documentation=https://doc.traefik.io/
After=network-online.target
Wants=network-online.target
[Service]
WorkingDirectory=/etc/traefik
EnvironmentFile=/etc/traefik/.env
ExecStart=/usr/local/bin/traefik --configFile=/etc/traefik/traefik.yaml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Все готово. На данный момент Traefik у нас установлен, но нам нужна конфигурация. И это по сути самое важное. После того как мы создадим статическую конфигурацию, нам нужно будет запустить этот systemd сервис и добавить его в автозагрузку. Я напомню об этом, в следующей статье. :)