Обо мне Блог Контакты

Обратный прокси 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 сервис и добавить его в автозагрузку. Я напомню об этом, в следующей статье. :)