Настройка SSL сертификатов для статического сайта в Docker

Введение

В этом руководстве мы настроим полную инфраструктуру для статического сайта my-site.ru:

  1. Развернем статический сайт в Docker контейнере
  2. Выпустим SSL сертификат Let’s Encrypt
  3. Настроим автоматическое обновление сертификата

Предварительные требования

  • Сервер с Ubuntu/Debian (root доступ)
  • Домен my-site.ru, указывающий на IP сервера
  • Открытые порты 80 и 443
  • Установленный Docker

Шаг 1: Подготовка статического сайта

1.1. Создайте структуру проекта

mkdir -p ~/my-site
cd ~/my-site

1.2. Создайте простую HTML страницу

cat > index.html << 'EOF'
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Мой сайт</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 50px;
            text-align: center;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
        }
        h1 { font-size: 3em; margin-bottom: 20px; }
        .container { max-width: 800px; margin: 0 auto; }
    </style>
</head>
<body>
    <div class="container">
        <h1>Мой сайт работает!</h1>
        <p>Сайт развернут в Docker контейнере</p>
        <p>SSL сертификат настроен через Let's Encrypt</p>
    </div>
</body>
</html>
EOF

1.3. Создайте Dockerfile

cat > Dockerfile << 'EOF'
FROM nginx:alpine

# Копируем статические файлы
COPY index.html /usr/share/nginx/html/
COPY 404.html /usr/share/nginx/html/

# Настройка Nginx
RUN echo 'server { \
    listen 80; \
    root /usr/share/nginx/html; \
    index index.html; \
    server_name localhost; \
    location / { \
        try_files $uri $uri/ =404; \
    } \
}' > /etc/nginx/conf.d/default.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
EOF

1.4. Создайте страницу 404

cat > 404.html << 'EOF'
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Страница не найдена</title>
</head>
<body>
    <h1>404 - Страница не найдена</h1>
    <a href="/">Вернуться на главную</a>
</body>
</html>
EOF

Шаг 2: Сборка и запуск Docker контейнера

2.1. Соберите Docker образ

docker build -t my-site:latest .

2.2. Запустите контейнер с пробросом порта

docker run -d \
  --name my-site \
  --restart unless-stopped \
  -p 9000:80 \
  my-site:latest

2.3. Проверьте работу контейнера

# Проверка статуса контейнера
docker ps | grep my-site

# Проверка доступа к сайту локально
curl -I http://localhost:9000

Шаг 3: Настройка Nginx на хосте как reverse proxy

3.1. Установите Nginx

sudo apt update
sudo apt install -y nginx

3.2. Создайте конфигурацию для сайта

sudo nano /etc/nginx/sites-available/my-site.ru

Вставьте настройки конфигурации в файл my-site.ru:

# HTTP - временная конфигурация для получения сертификата
server {
    listen 80;
    server_name my-site.ru www.my-site.ru;

    location / {
        proxy_pass http://localhost:9000;
        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;
    }
}

3.3. Активируйте конфигурацию

# Создайте симлинк
sudo ln -s /etc/nginx/sites-available/my-site.ru /etc/nginx/sites-enabled/

# Проверьте конфигурацию
sudo nginx -t

# Перезагрузите Nginx
sudo systemctl reload nginx

Шаг 4: Выпуск SSL сертификата Let’s Encrypt

4.1. Установите Certbot

sudo apt update
sudo apt install -y certbot python3-certbot-nginx

4.2. Получите сертификат

sudo certbot --nginx -d my-site.ru -d www.my-site.ru

Во время установки:

  • Введите email для уведомлений
  • Согласитесь с условиями использования
  • Выберите, перенаправлять ли HTTP на HTTPS (рекомендуется выбрать 2)

4.3. Проверьте сертификат

sudo certbot certificates

Вы должны увидеть:

Certificate Name: my-site.ru
Domains: my-site.ru www.my-site.ru
Expiry Date: 2026-06-03 (VALID: 89 days)

Шаг 5: Финальная конфигурация Nginx с SSL

Certbot автоматически обновил конфигурацию Nginx. Проверьте её:

sudo cat /etc/nginx/sites-available/my-site.ru

Конфигурация должна выглядеть примерно так:

server {
    server_name my-site.ru www.my-site.ru;

    location / {
        proxy_pass http://localhost:9000;
        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;
    }

    listen 443 ssl;
    ssl_certificate /etc/letsencrypt/live/my-site.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/my-site.ru/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}

server {
    if ($host = www.my-site.ru) {
        return 301 https://$host$request_uri;
    }
    if ($host = my-site.ru) {
        return 301 https://$host$request_uri;
    }

    listen 80;
    server_name my-site.ru www.my-site.ru;
    return 404;
}

Шаг 6: Настройка автоматического обновления сертификатов

6.1. Проверьте системный таймер certbot

# Проверьте статус таймера
sudo systemctl status certbot.timer

# Посмотрите время следующего запуска
sudo systemctl list-timers --all | grep certbot

6.2. Настройте перезапуск Nginx после обновления

Создайте deploy hook:

sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

Вставьте скрипт:

#!/bin/bash
systemctl reload nginx

Сделайте его исполняемым:

sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

6.3. Проверьте конфигурацию обновления

# Тестовый прогон
sudo certbot renew --dry-run

Шаг 7: Мониторинг и проверка

7.1. Создайте скрипт для проверки статуса

sudo nano /usr/local/bin/check-ssl-status.sh
#!/bin/bash

DOMAIN="my-site.ru"

echo "=== СТАТУС SSL СЕРТИФИКАТА ==="
sudo certbot certificates | grep -A 3 "Certificate Name: $DOMAIN"

echo -e "\n=== ТАЙМЕР АВТООБНОВЛЕНИЯ ==="
sudo systemctl status certbot.timer --no-pager | grep -E "Active|Trigger"

echo -e "\n=== ПОСЛЕДНЕЕ ОБНОВЛЕНИЕ ==="
sudo journalctl -u certbot.service --since "1 week ago" | grep -E "renew|Certificate" | tail -5

echo -e "\n=== СТАТУС КОНТЕЙНЕРА ==="
docker ps --filter "name=my-site" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

echo -e "\n=== СТАТУС NGINX ==="
sudo systemctl status nginx --no-pager | grep "Active"

Сделайте скрипт исполняемым:

sudo chmod +x /usr/local/bin/check-ssl-status.sh

7.2. Проверьте работу сайта

# Проверка HTTP -> HTTPS перенаправления
curl -I http://my-site.ru

# Проверка HTTPS
curl -I https://my-site.ru

# Проверка сертификата
echo | openssl s_client -connect my-site.ru:443 -servername my-site.ru 2>/dev/null | openssl x509 -noout -dates

Проверка работоспособности

Быстрая диагностика одной командой:

sudo /usr/local/bin/check-ssl-status.sh

Откройте сайт в браузере

Перейдите по адресу https://my-site.ru - вы должны увидеть созданную HTML страницу с зеленым замком в адресной строке.

Устранение возможных проблем

Проблема: Сертификат не обновляется автоматически

# Проверьте логи
sudo journalctl -u certbot.service -f

# Запустите обновление вручную
sudo certbot renew --force-renewal

Проблема: Nginx не перезапускается после обновления

# Проверьте hook
sudo ls -la /etc/letsencrypt/renewal-hooks/deploy/
sudo cat /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

# Проверьте права
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

Проблема: Контейнер не запускается

# Проверьте логи контейнера
docker logs my-site

# Перезапустите контейнер
docker restart my-site

Ваш сайт защищен и будет автоматически поддерживать актуальный SSL сертификат без вашего участия!

Полезные команды для ежедневного использования

# Проверка статуса сертификата
sudo certbot certificates

# Ручное обновление (если нужно)
sudo certbot renew

# Просмотр логов обновления
sudo journalctl -u certbot.service -f

# Перезапуск контейнера
docker restart my-site

# Просмотр логов контейнера
docker logs my-site

# Проверка конфигурации Nginx
sudo nginx -t
sudo systemctl reload nginx

Полезные ссылки