Прикрутить домен к серверу и получить ssl-сертификат для https
Автор: Pans
Специфика данного проекта в том, что nginx запущен в докере, но принцип тот же и если он просто установлен на сервере, просто не редактируем docker-compose.yml для nginx.
Так же мой проект написан на django, конкретно для него пункт 5.5
План по подключению https:
Шаг 1 - купить домен и добавить A-запись
Шаг 2 - подождать propagation - проверим через dig или dnschecker.org
Шаг 3 - установить certbot на хост (не в Docker) и получить сертификат
Шаг 4 - обновить nginx.conf - добавить прослушку 443 порта и редирект с 80
Шаг 5 - обновить docker-compose.yml - пробросить порт 443, примонтировать папку с сертификатами в nginx-контейнер
Шаг 6 - настроить автообновление сертификата
1.)
VPS покупал у хостинг провайдера, у него же была услуга по покупке домена, выбираешь понравившийся-незанятый. Иногда у него же(этого хостинг провайдера) в настройках домена можно самостоятельно добавить А-запись(ну или через какой-нибудь тикет/почту если у твоего нет)
Тип Имя Значение
A @ <ip-адрес сервера>
Имя указывается именно @ это указание что имя без поддоменов.
2.)
Затем ждем от пары минут до 72 часов. Проверяем через
# win
nslookup your-domain.ru
# ubuntu
dig your-domain.ru +short
или онлайн, неплохой вариант https://dnschecker.org/ сразу по разным регионам проверить.
В моем случае прошло часа 2-3
C:\Users\Pans>nslookup viking-san.ru 8.8.8.8
╤хЁтхЁ: dns.google
Address: 8.8.8.8
Не заслуживающий доверия ответ:
╚ь : viking-san.ru
Address: 138.124.59.65
3.)
certbot установим на хосте
# обновим систему
sudo apt update && sudo apt upgrade -y
# установим сам certbot
sudo apt install certbot -y
Перед тем как непосредственно запросить сертификат нужно на nginx разрешить маршрут к /.well-known/acme-challenge/ в 80 порту
# в nginx.conf в начале блока server добавить маршрут
server {
listen 80;
# путь используемый для автоматической проверки прав на домен для выпуска SSL/TLS-сертификатов
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# ... остальное без изменений
И в docker nginx-volumes добавить рабочую директорию certbot, сразу можно и 443 порт открыть
# docker-compose.yml
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443" # добавить 443 порт
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
- /var/www/certbot:/var/www/certbot:ro # добавить рабочую директорию certbot
# ... остальное без изменений
После внесения изменений нужно перезапустить nginx
docker compose restart nginx
# ну и проверить что все контейнеры на месте
docker ps
Теперь получаем сертификат
sudo certbot certonly --webroot -w /var/www/certbot -d your-domain.ru
Он попросит почту, туда будут приходить уведомления, лучше использовать настояющую, про дополнительные новости на эту почту от них он спросит отдельно, можно отказаться или согласиться. А вот согласится с их Terms of Service нужно.
Если все ок, он выдаст что-то типо
Account registered.
Requesting a certificate for viking-san.ru
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/viking-san.ru/fullchain.pem
Key is saved at: /etc/letsencrypt/live/viking-san.ru/privkey.pem
This certificate expires on 2026-07-08.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Поздравляю теперь есть сертификат!
Как говорится в сообщении он сам установил таск на обновление сертификата.
Проверить можно
systemctl status certbot.timer
Но проблема в том что в этот момент nginx будет работать, скорей всего, и держать используемый(старый) сертификат в памяти. Но к этому мы вернемся в 6 Шаге
4.)
Редактируем nginx.conf
В 80 порту оставляем только маршрут для обновления сертификата и редирект на https.
Еще правилом хорошего тона является добавить server_name, даже если пока только один домен
server {
listen 80;
# Слушаем входящие соединения на порту 80 (стандартный HTTP)
server_name viking-san.ru;
location /.well-known/acme-challenge/ {
# ssl сертификаты отдаём напрямую
root /var/www/certbot;
}
location / {
# Перенаправляем все запросы на HTTPS
return 301 https://$host$request_uri;
}
}
И добавляем - слушать 443 порт, куда переносим все остальные маршруты
server{
listen 443 ssl;
# слушать https трафик на 443 порту
server_name viking-san.ru;
ssl_certificate /etc/letsencrypt/live/viking-san.ru/fullchain.pem;
# Путь к сертификату и цепочка доверия
ssl_certificate_key /etc/letsencrypt/live/viking-san.ru/privkey.pem;
# Путь к ключу сертификата, никому не показывать содержимое
# все остальные маршруты
...
}
5.)
Добавляем в docker-compose.yml в nginx-volumes директорию с сертификатами
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
- /var/www/certbot:/var/www/certbot:ro
- /etc/letsencrypt:/etc/letsencrypt:ro # ssl сертификаты хранятся отдельно от docker
# ... остальное без изменений
5.5) настройка django
В целом теперь есть домен, ssl-сертификат. Можно ходить по имени по https.
Но в моем случае нужно настроить разрешенные хосты и всякое такое в django.
В .env файле или где-то в settings лежат переменные ALLOWED_HOSTS и CSRF_TRUSTED_ORIGINS, добавляем к ним(или меняем значения на) доступ по домену
ALLOWED_HOSTS=viking-san.ru
CSRF_TRUSTED_ORIGINS=https://viking-san.ru
Так же у меня поднят minio как s3 хранилище. Для отображения картинок ему нужно так же изменить
MINIO_CUSTOM_DOMAIN=viking-san.ru/media
В продакшен версии стоит подключить
# SECURE_SSL_REDIRECT = True # nginx уже редиректит на https, если включить, то доступ по ip сломается.
# просто говорят браузеру не отправлять куки по HTTP
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# браузер запомнит что сайт только HTTPS
# и будет игнорировать HTTP даже если ты потом уберёшь редирект
SECURE_HSTS_SECONDS = 3600
6.)
Если на данном этапе все работает, то ты классный.
Сертификат выдается на 90 дней. В любой момент можно посмотреть дату истечения выданного сертификата
sudo certbot certificates
И теперь остается только проблема с nginx, который держит в памяти сертификат и, после получения обновленного через certbot, не знает о новом.
Для решения этой проблемы есть --deploy-hook
certbot создает директорию
/etc/letsencrypt/renewal-hooks/deploy/
В которую можно положить скрипты которые будут исполняться когда он будет обновлять сертификат.
Сначала сделаем через рестарт nginx по этому событию, чтобы увидеть результат в логах, потом поправим.
Создаем скрипт
sudo vim /etc/letsencrypt/renewal-hooks/deploy/restart-nginx.sh
с содержимым
#!/bin/sh
cd ~/projects/learning-journal
docker compose restart nginx
И делаем исполняемым
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/restart-nginx.sh
Чтобы просто потестить работает ли обновление сертификатов можно запросить Let's Encrypt выдать тестовый сертификат на своём staging-сервере, при этом нигде на сервере он не сохранится
sudo certbot renew --dry-run
Но для проверки хука это не годится.
Можно принудительно выпустить новый сертификат, игнорируя срок действия. Использовать осторожно из-за лимитов Let's Encrypt - не более 5 запросов в неделю для одного набора доменов.
sudo certbot renew --force-renewal
Однако если хук настроен корректно, то он скажет что-то вроде
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/viking-san.ru.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Renewing an existing certificate for viking-san.ru
Hook 'deploy-hook' ran with error output:
Container learning-journal-nginx-1 Restarting
Container learning-journal-nginx-1 Started
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all renewals succeeded:
/etc/letsencrypt/live/viking-san.ru/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Значит все точно ок. Правда рестартить nginx так себе решение проблемы, можно сделать "мягкий" релоад, исправляем скрипт
#!/bin/sh
cd ~/projects/learning-journal
docker compose exec nginx nginx -s reload
Комментарии (0)
Пока нет комментариев.