---
author: Pans
category: Обучение
tags:
- certbot
- devops
- domain
- https
- letsencrypt
- ssl
title: Прикрутить домен к серверу и получить ssl-сертификат для https
---

*Специфика данного проекта в том, что 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
```