О насБлогКонтакты
DevOps10 декабря 2015 г. 4 мин 23

Как установить Let's Encrypt на nginx — первые дни после запуска (декабрь 2015)

AunimedaAunimeda
📋 Содержание

Как установить Let's Encrypt на nginx — первые дни после запуска (декабрь 2015)

Коротко: Скачайте letsencrypt-auto с GitHub (pip-пакет ещё не существовал), запустите ./letsencrypt-auto --nginx -d mysite.ru. В декабре 2015 плагин nginx был нестабилен — надёжнее использовать --webroot с ручным обновлением nginx конфига. Автопродление через cron.


Контекст: первые дни Let's Encrypt

3 декабря 2015 — Let's Encrypt перешёл в публичную бету. До этого — invites. До этого — платные сертификаты $10-150/год.

Мы установили Let's Encrypt на 8 клиентских серверов в первую же неделю. На 5 — с первой попытки. На 3 — пришлось разбираться.


Установка (декабрь 2015 — до существования certbot в apt)

# Certbot ещё не был в репозиториях Ubuntu — только GitHub
sudo apt-get install git

git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt
cd /opt/letsencrypt

# Автоматически устанавливает зависимости через virtualenv
./letsencrypt-auto --help

# На Ubuntu 14.04 может потребоваться обновление pip:
# ./letsencrypt-auto требует Python 2.7 и virtualenv
sudo apt-get install python python-pip python-virtualenv -y

Получение сертификата (webroot метод — надёжнее nginx плагина)

# Временный nginx конфиг для получения сертификата
server {
    listen 80;
    server_name mysite.ru www.mysite.ru;
    
    root /var/www/mysite;
    
    # Let's Encrypt проверяет владение доменом через этот путь
    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt;
        try_files $uri =404;
    }
    
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
}
sudo mkdir -p /var/www/letsencrypt
sudo nginx -t && sudo service nginx reload

# Получить сертификат
cd /opt/letsencrypt
./letsencrypt-auto certonly \
    --webroot \
    --webroot-path=/var/www/letsencrypt \
    -d mysite.ru \
    -d www.mysite.ru \
    --email admin@mysite.ru \
    --agree-tos

# Успех: сертификаты в /etc/letsencrypt/live/mysite.ru/
# - fullchain.pem  — ваш сертификат + промежуточные CA
# - privkey.pem    — приватный ключ
# - cert.pem       — только ваш сертификат (обычно не нужен)
# - chain.pem      — только промежуточные CA (обычно не нужен)

Nginx конфиг с Let's Encrypt сертификатом

# /etc/nginx/sites-available/mysite — финальная версия

server {
    listen 80;
    server_name mysite.ru www.mysite.ru;
    
    # Let's Encrypt renewal challenge
    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt;
    }
    
    # Всё остальное — редирект на HTTPS
    location / {
        return 301 https://mysite.ru$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name www.mysite.ru;
    
    ssl_certificate     /etc/letsencrypt/live/mysite.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mysite.ru/privkey.pem;
    
    return 301 https://mysite.ru$request_uri;
}

server {
    listen 443 ssl;
    server_name mysite.ru;

    ssl_certificate     /etc/letsencrypt/live/mysite.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mysite.ru/privkey.pem;

    # TLS конфигурация (Mozilla Intermediate 2015)
    ssl_protocols             TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers               ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK;
    ssl_prefer_server_ciphers on;
    ssl_session_cache         shared:SSL:10m;
    ssl_session_timeout       10m;
    ssl_stapling              on;
    ssl_stapling_verify       on;

    add_header Strict-Transport-Security "max-age=31536000" always;

    root  /var/www/mysite;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass   unix:/var/run/php5-fpm.sock;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

Автопродление через cron

# Сертификаты Let's Encrypt действительны 90 дней
# letsencrypt-auto renew проверяет и продлевает за 30 дней до истечения

crontab -e
# Добавить (запуск в 3:00 и 15:00 каждый день):
0 3,15 * * * /opt/letsencrypt/letsencrypt-auto renew --quiet && service nginx reload
# Проверить что автопродление работает
/opt/letsencrypt/letsencrypt-auto renew --dry-run
# Должно напечатать: "No renewals were attempted" или "Simulating renewal of..."
# НЕ должно быть ошибок

Проблемы первых недель

Проблема: "Name or service not known" при certbot

Let's Encrypt OCSP серверы временами были недоступны из России в первые недели. Решение:

# Повторить через несколько часов
# В декабре 2015 серверы LE работали нестабильно из-за нагрузки

Проблема: Nginx плагин ломает конфиг

# --nginx плагин в декабре 2015 часто некорректно модифицировал nginx.conf
# Безопаснее: --webroot + ручное редактирование конфига
./letsencrypt-auto certonly --webroot ...  # Только получить сертификат
# Конфиг nginx прописать вручную (как выше)

Проблема: Сертификат получен, но браузер показывает ошибку

# Проверить цепочку сертификатов
openssl s_client -connect mysite.ru:443 -showcerts 2>/dev/null | openssl x509 -noout -issuer -subject

# fullchain.pem должен содержать и ваш сертификат, и промежуточные CA
# Если использовали cert.pem вместо fullchain.pem — браузер не доверяет

Итог: что изменилось для рынка

До декабря 2015: HTTPS на сайте клиента = $10-150/год + час работы по настройке = часто пропускали.

После: HTTPS бесплатно + один раз настроил автопродление = у каждого нового сайта HTTPS по умолчанию.

За следующие 12 месяцев мы перевели на HTTPS все 40+ активных клиентских сайтов. Ни один не требовал повторного вмешательства — автопродление работало без проблем.

Читайте также

Как хранить сессии в Redis для нескольких серверов PHP (2016)aunimeda
DevOps

Как хранить сессии в Redis для нескольких серверов PHP (2016)

При горизонтальном масштабировании PHP на 2+ серверов сессии перестают работать: пользователь авторизован на сервере 1, запрос попадает на сервер 2 — сессия не найдена. Решение: хранить сессии в Redis, к которому имеют доступ все серверы. Настройка PHP, nginx upstream, Redis.

Как настроить CI/CD для PHP-проекта в GitLab в 2016 годуaunimeda
DevOps

Как настроить CI/CD для PHP-проекта в GitLab в 2016 году

GitLab CI стал бесплатным и встроенным в GitLab CE в 2015. В 2016 мы перешли с ручных деплоев по FTP на автоматическую сборку и деплой при каждом push в master. Точная конфигурация .gitlab-ci.yml: тесты PHPUnit, статический анализ, деплой по SSH без downtime.

Хабраэффект 2011: как пост на Хабре положил наш сервер и что мы с этим сделалиaunimeda
DevOps

Хабраэффект 2011: как пост на Хабре положил наш сервер и что мы с этим сделали

«Хабраэффект» — это когда публикация на Хабрахабр за 15 минут уничтожает сервер, который нормально работал месяцами. Мы через это прошли в 2011 году. Вот технический разбор того, что упало, почему упало и как мы перестроили стек чтобы это не повторилось.

Нужна IT-разработка для вашего бизнеса?

Разрабатываем сайты, мобильные приложения и AI-решения для бизнеса в России. Бесплатная консультация.

Получить консультацию Все статьи