Пошук уроків, статей та іншого контенту
Підключите TLS-сертифікати, перенаправлення на HTTPS і автоматичне оновлення сертифікатів.
TLS зазвичай завершується на зворотному проксі — наприклад, Nginx:
Клієнт
│ HTTPS :443
▼
Nginx-контейнер
│ HTTP у внутрішній Docker-мережі
▼
Контейнер застосункуNginx відповідає за:
використання TLS-сертифіката;
перенаправлення HTTP на HTTPS;
обробку ACME-запитів для Let's Encrypt;
проксування запитів до застосунку.
Сертифікати та приватні ключі зберігаються у volume, щоб не втрачати їх під час оновлення контейнера.
Для прикладу використаємо:
домен example.com;
додаткове ім’я www.example.com;
Nginx;
Certbot;
застосунок, який слухає порт 3000.
Перед отриманням сертифіката необхідно:
Створити DNS-записи A або AAAA для домену.
Переконатися, що домен вказує на сервер із Docker.
Відкрити порти 80 і 443 у firewall.
Замінити example.com у конфігурації на власний домен.
Let's Encrypt перевіряє володіння доменом через HTTP-запит до шляху:
http://example.com/.well-known/acme-challenge/...Тому порт 80 має бути доступним навіть після налаштування HTTPS.
Створимо таку структуру:
project/
├── compose.yml
└── nginx/
└── nginx.confФайл compose.yml:
services:
app:
image: node:20-alpine
command:
- node
- -e
- |
require("http").createServer((req, res) => {
res.writeHead(200, {"Content-Type": "text/plain; charset=utf-8"});
res.end("Застосунок працює у контейнері\n");
}).listen(3000, "0.0.0.0");
networks:
- web
nginx:
image: nginx:1.27-alpine
depends_on:
- app
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- letsencrypt:/etc/letsencrypt
- certbot-www:/var/www/certbot
networks:
- web
certbot:
image: certbot/certbot:latest
volumes:
- letsencrypt:/etc/letsencrypt
- certbot-www:/var/www/certbot
networks:
- web
volumes:
letsencrypt:
certbot-www:
networks:
web:Сервіс app — це мінімальний приклад застосунку. У реальному проєкті його буде замінено власним контейнером.
Сервіси nginx і certbot використовують спільні volumes:
letsencrypt містить сертифікати та приватні ключі;
certbot-www містить файли ACME-перевірки.
На першому етапі сертифікатів ще немає, тому Nginx має працювати лише через HTTP.
Створіть nginx/nginx.conf:
events {}
http {
upstream application {
server app:3000;
}
server {
listen 80;
server_name example.com www.example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
proxy_pass http://application;
proxy_http_version 1.1;
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;
}
}
}Важливо, що root /var/www/certbot відповідає шляху, до якого змонтовано volume certbot-www.
Запустіть Nginx і застосунок:
docker compose up -d app nginxПеревірте HTTP-доступ:
curl http://example.comЯкщо DNS і firewall налаштовані правильно, відповідь надійде від контейнера app.
Запустіть Certbot у режимі webroot:
docker compose run --rm certbot certonly \
--webroot \
--webroot-path=/var/www/certbot \
--email admin@example.com \
--agree-tos \
--no-eff-email \
-d example.com \
-d www.example.comПараметри команди:
certonly — отримати сертифікат без автоматичної зміни конфігурації Nginx;
--webroot — розмістити файл перевірки у вказаному каталозі;
--email — адреса для сповіщень про сертифікат;
--agree-tos — прийняття умов Let's Encrypt;
-d — доменні імена, для яких видається сертифікат.
Після успішного виконання сертифікати будуть доступні за такими шляхами:
/etc/letsencrypt/live/example.com/fullchain.pem
/etc/letsencrypt/live/example.com/privkey.pemЦі шляхи існують усередині volume, змонтованого до контейнера Nginx.
Тепер замініть вміст nginx/nginx.conf на конфігурацію з HTTP і HTTPS:
events {}
http {
upstream application {
server app:3000;
}
server {
listen 80;
server_name example.com www.example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
location / {
proxy_pass http://application;
proxy_http_version 1.1;
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 https;
}
}
}У цьому конфігу:
HTTP-запити до звичайних шляхів отримують відповідь 301;
$host зберігає доменне ім’я;
$request_uri зберігає шлях і query-параметри;
ACME-шлях залишається доступним через HTTP;
HTTPS-запити проксуються до контейнера app.
Наприклад, запит:
http://example.com/products?page=2буде перенаправлено на:
https://example.com/products?page=2Перевірте конфігурацію і перезавантажте Nginx:
docker compose exec nginx nginx -t
docker compose exec nginx nginx -s reloadКоманда nginx -t перевіряє синтаксис і наявність файлів сертифіката. Не перезавантажуйте Nginx, якщо ця перевірка завершилася помилкою.
Тепер перевірте перенаправлення:
curl -I http://example.comОчікуваний результат міститиме:
HTTP/1.1 301 Moved Permanently
Location: https://example.com/Перевірка HTTPS:
curl -I https://example.comСертифікати Let's Encrypt мають обмежений строк дії. Certbot може оновити сертифікат командою:
docker compose run --rm certbot renew \
--webroot \
--webroot-path=/var/www/certbotКоманда renew оновлює лише ті сертифікати, для яких уже настав час оновлення. Її можна запускати регулярно, наприклад один або два рази на добу.
Оновлений сертифікат не почне використовуватися вже запущеним Nginx автоматично. Після оновлення потрібно перечитати сертифікати:
docker compose exec -T nginx nginx -s reloadОдин із варіантів автоматизації на сервері — cron:
17 3 * * * cd /opt/my-app && docker compose run --rm certbot renew --webroot --webroot-path=/var/www/certbot && docker compose exec -T nginx nginx -s reloadЗамініть /opt/my-app на фактичний шлях до проєкту.
У цьому прикладі:
Certbot перевіряє, чи потрібно оновити сертифікат.
Якщо команда завершилася успішно, Nginx перечитує сертифікати.
Застосунок і Nginx не перезапускаються повністю.
Перед використанням cron переконайтеся, що команда працює вручну:
cd /opt/my-app
docker compose run --rm certbot renew --webroot --webroot-path=/var/www/certbot
docker compose exec -T nginx nginx -s reloadПеревірте основні сценарії:
curl -I http://example.com
curl -I https://example.com
curl https://example.comПотрібно переконатися, що:
HTTP перенаправляється на HTTPS;
HTTPS повертає відповідь застосунку;
сертифікат виданий для правильного домену;
ACME-шлях доступний через HTTP;
після оновлення сертифіката Nginx перечитує його без помилок.
Також корисно перевірити журнали:
docker compose logs nginx
docker compose logs certbotЯкщо в конфігурації одразу вказані:
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;але сертифікат ще не отримано, Nginx завершиться з помилкою.
Спочатку використовуйте HTTP-конфігурацію, отримайте сертифікат, а потім увімкніть HTTPS-конфігурацію.
Let's Encrypt не зможе виконати HTTP-перевірку, якщо порт 80 закритий у firewall або не проброшений у Docker Compose.
Переконайтеся, що є такі mappings:
ports:
- "80:80"
- "443:443"Перевірка сертифіката виконується із зовнішньої мережі. Внутрішній DNS-запис або запис на локальну адресу не підходить для публічного сертифіката Let's Encrypt.
Не слід перенаправляти шлях /.well-known/acme-challenge/ до HTTPS до моменту, коли перевірка завершена. Саме тому для нього існує окремий location.
Nginx передає застосунку заголовок:
proxy_set_header X-Forwarded-Proto https;Це повідомляє застосунку, що початковий запит був HTTPS, навіть якщо між Nginx і застосунком використовується звичайний HTTP.
Після оновлення файлів Nginx ще використовує сертифікат, завантажений у пам’ять. Виконайте:
docker compose exec -T nginx nginx -s reloadСертифікати не потрібно копіювати через COPY у Dockerfile або зберігати в репозиторії. Використовуйте volume і обмежте доступ до сервера та конфігурації.
TLS можна завершувати в окремому Nginx-контейнері.
Сертифікати Certbot і Nginx мають зберігати у спільному volume.
Для першого сертифіката зручно використовувати режим webroot.
HTTP має залишатися доступним для ACME-перевірок.
Звичайні HTTP-запити потрібно перенаправляти на HTTPS через 301.
Після автоматичного оновлення сертифіката Nginx необхідно перезавантажити або виконати graceful reload.
До першого отримання сертифіката слід використовувати окрему HTTP-конфігурацію, інакше Nginx не запуститься.