# Traefik: reverse proxy з автоматичним TLS для Docker

> Traefik сам знаходить контейнери Docker і випускає TLS-сертифікати через Let's Encrypt без ручних конфігів. Встановлення, labels і типові помилки.

Traefik — reverse proxy, який сам знаходить контейнери Docker і сам випускає TLS-сертифікати, без ручної правки конфігів при кожному новому сайті. Замість статичного файлу з блоками server, як у nginx, Traefik читає labels прямо на контейнерах і перебудовує маршрути на льоту. Розберемо встановлення в Docker Compose, автоматичний TLS через Let's Encrypt і типові помилки.

## Що таке Traefik і чим він відрізняється від nginx

nginx потребує окремого конфіг-файлу на кожен сайт і перезавантаження процесу при змінах. Traefik підключається до Docker через сокет, бачить усі запущені контейнери і будує маршрути з їхніх labels автоматично — без reload і без окремих файлів конфігурації на кожен домен. Новий сайт додається одним рядком labels у `docker-compose.yml`, а не окремим конфігом reverse proxy.

Зворотний бік: Traefik додає ще один шар абстракції поверх звичного HTTP-сервера, і відлагодження маршрутів доводиться вести через його власний дашборд, а не через звичні логи nginx.

## Встановлення Traefik у Docker Compose

Базовий сервіс Traefik у `docker-compose.yml` із увімкненим Docker-провайдером:

```
services:
  traefik:
    image: traefik:v3.1
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
    restart: unless-stopped
```

Прапорець `exposedbydefault=false` обов'язковий: без нього Traefik відкриває назовні взагалі всі контейнери на сервері, а не лише ті, що явно позначені labels.

## Автоматичний TLS через Let's Encrypt

Traefik сам запитує і подовжує сертифікати через протокол ACME, без cron-завдання й окремого certbot. Для цього до команди сервісу додають resolver:

```
command:
  - --certificatesresolvers.le.acme.email=admin@example.com
  - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
  - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
```

Файл `acme.json` повинен мати права 600 — Let's Encrypt зберігає в ньому приватні ключі сертифікатів, і за більш відкритих прав Traefik відмовиться його використовувати.

## Як Traefik знаходить контейнери: labels на сервісах

Кожен контейнер, який повинен отримати маршрут, позначається labels прямо в описі сервісу:

```
services:
  app:
    image: myapp:latest
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app.rule=Host(`app.example.com`)"
      - "traefik.http.routers.app.entrypoints=websecure"
      - "traefik.http.routers.app.tls.certresolver=le"
      - "traefik.http.services.app.loadbalancer.server.port=8080"
```

Traefik сам підхоплює контейнер після `docker compose up -d`: не треба окремо редагувати конфіг proxy і перезапускати його.

## Декілька сайтів на одному сервері

Маршрутизація за доменами тримається на правилі `Host()` у labels: різні контейнери відповідають на різні домени через той самий порт 443 сервісу Traefik. Для кожного домену задається свій `certresolver`, і Traefik випускає окремий сертифікат на кожен Host автоматично при першому запиті.

| Критерій | Traefik | Caddy |
| --- | --- | --- |
| Виявлення сервісів | Автоматично через Docker labels | Через статичний Caddyfile |
| Автоматичний TLS | Так, через ACME resolver | Так, одразу для будь-якого домену |
| Перезавантаження при новому сайті | Не потрібне | Потрібен reload конфіга |

## Дашборд і спостереження за маршрутами

Вбудований дашборд на порту 8080 показує перелік роутерів, сервісів і middleware в реальному часі — зручно перевірити, що labels розпізнані правильно. У продакшені дашборд закривають тим самим механізмом labels з basic-auth middleware, а не залишають відкритим назовні.

- Увімкнути дашборд прапорцем `--api.dashboard=true` лише на етапі відлагодження
- Закрити шлях `/dashboard/` окремим роутером з middleware авторизації
- Дивитися логи access через `--accesslog=true` під час розбору проблем із маршрутизацією

## Поширені помилки конфігурації

Перша помилка — забутий `exposedbydefault=false`, через що назовні відкриваються службові контейнери на кшталт баз даних. Друга — неправильні права на `acme.json`, через які Traefik тихо не може зберегти сертифікат і перевипускає його при кожному рестарті, впираючись у ліміти Let's Encrypt. Третя — відсутність `traefik.enable=true` на потрібному контейнері, через що сервіс лишається недоступним, хоча всі інші labels виставлені правильно.

Якщо сайтів на сервері багато і потрібен кластер з кількох VDS, той самий Traefik працює і поверх [Docker Swarm](https://www.zevshost.net/uk/kb/docker-swarm-nastroika/), читаючи labels вже з режиму stack. Для порівняння з простішим за конфігурацією reverse proxy дивіться статтю про [Caddy Server](https://www.zevshost.net/uk/kb/caddy-server-nastroika/). Якщо інфраструктура вже перейшла на повноцінний Kubernetes, аналогічну роль там виконує [ingress-nginx](https://www.zevshost.net/uk/kb/kubernetes-ingress-nginx/).

## Підсумок: чекліст запуску Traefik

Traefik позбавляє від ручного редагування конфігів reverse proxy при кожному новому контейнері, якщо labels налаштовані акуратно з самого початку.

- Прапорець `exposedbydefault=false` у конфігурації Docker-провайдера
- Права 600 на файл `acme.json` із сертифікатами
- `traefik.enable=true` явно на кожному контейнері, який повинен бути видимим назовні
- Дашборд закритий middleware авторизації, а не відкритий на весь інтернет

## Часті питання

### Чи можна через Traefik проксувати трафік не на Docker-контейнер, а на зовнішній сервер або IP-адресу?

Механізм labels, описаний у статті, розрахований саме на контейнери Docker, які Traefik бачить через сокет сам. Для маршрутизації на зовнішній сервер чи адресу поза Docker потрібен окремий провайдер статичної конфігурації, а не labels на контейнері — налаштування в цьому випадку виходить більш ручним і не таким автоматичним, як для локальних сервісів.

### Контейнер запущено з правильними labels, але назовні він все одно недоступний — у чому може бути причина?

Найчастіше бракує одного рядка в labels, який явно дозволяє Traefik бачити саме цей контейнер — без нього сервіс лишається невидимим, навіть якщо решта правил маршрутизації описана правильно. Варто також перевірити, що прапорець, який обмежує автоматичний показ контейнерів назовні, не блокує саме цей сервіс за умовчанням.

### Чи потрібно вручну подовжувати сертифікати Let's Encrypt, випущені через Traefik?

Ні, саме в цьому і полягає зручність вбудованого ACME resolver — Traefik сам стежить за строком дії сертифіката і запитує новий заздалегідь, без окремого cron-завдання і без участі людини. Єдина умова — файл, де зберігаються сертифікати, повинен мати правильні права доступу, інакше Traefik не зможе записати туди оновлені дані під час подовження.

### Чи варто переходити на Traefik, якщо на сервері вже працює nginx і сайтів небагато?

Якщо сайтів мало і конфіги майже не змінюються, вигода від автоматичного виявлення контейнерів невелика, а розбиратися ще з одним шаром абстракції і окремим дашбордом замість звичних логів nginx — зайві зусилля. Перехід виправданий, коли нові сайти і контейнери зʼявляються часто і ручна правка конфіга reverse proxy щоразу перетворюється на помітну рутину.

---

Джерело: https://www.zevshost.net/uk/kb/traefik-reverse-proxy/
