← Назад к списку

Прикрутить домен к серверу и получить ssl-сертификат для https

Автор: Pans

Обучение Создано: 09 April 2026, 15:28 | Изменено: 10 April 2026, 17:43

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

Пока нет комментариев.


Вы оставите комментарий как Anonymous/Deleted User Войти