Skip to content

Instantly share code, notes, and snippets.

@artrey
Last active October 22, 2023 15:30
Show Gist options
  • Save artrey/0385dc633f4d909496f7adb23bc9b13b to your computer and use it in GitHub Desktop.
Save artrey/0385dc633f4d909496f7adb23bc9b13b to your computer and use it in GitHub Desktop.
nginx + certbot
  1. Установить nginx и certbot
apt install nginx certbot
  1. Создаем/изменяем файл с настройками получения сертификатов (метод webroot). Файл /etc/letsencrypt/cli.ini
authenticator = webroot
webroot-path = /var/www/html
post-hook = service nginx reload
text = True
  1. Создаем папку, в которой certbot будет проверять файлы (именно такая)
mkdir -p /var/www/html/.well-known/acme-challenge
  1. Регистрируем certbot (одноразовая оперция)
certbot register --email me@example.com

или без почты (но сам letsencrypt не рекомендует, он не сможет уведомлять о проблемах):

certbot register --register-unsafely-without-email
  1. Создаем шаблон для всех сайтов (которым нужен сертификат). Файл /etc/nginx/acme
location /.well-known {
    root /var/www/html;
}
  1. Перед всеми блоками location вставляем запись
include acme;
  1. Пробуем получить сертификаты
certbot certonly --dry-run -d example.com -d sub.example.com
  1. Если все ОК (есть строка The dry run was successful), то выписываем сертификаты
certbot certonly -d example.com -d sub.example.com
  1. Настраиваем автопродление. Дописать к вызову certbot в /etc/cron.d/certbot ключ --allow-subset-of-names (это чтобы при отвале одного из доменов другие продолжали выписываться):
# последняя строка в /etc/cron.d/certbot
# было certbot -q renew, а надо
certbot -q renew --allow-subset-of-names

Wildcard сертификаты

  1. Проверяем корректность команды и получаем строчку, которую нужно будет прописать в DNS
certbot certonly --dry-run --manual --agree-tos --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory -d *.example.com

В конце получим примерно такое сообщение:

Please deploy a DNS TXT record under the name
_acme-challenge.example.com with the following value:

3yTQ7zcagxbrWLdLI4Jp8wA_VarDKkAt7RqCOwjugaE

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
  1. Добавляем DNS TXT запись и ожидаем некоторое время, пока запись обновится у регистратора

Проверить можно так:

dig -t txt _acme-challenge.example.com
  1. Когда запись будет установлена - нажимаем Enter

  2. Запускаем команду на получение сертификата (все тоже самое, только без --dry-run)

certbot certonly --manual --agree-tos --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory -d *.example.com

Полезное

  • Если хочется добавить поддомен или домен:
certbot certonly --expand -d example.com -d www.example.com -d shop.example.com
  • Пример конфига
server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;

        server_name site.name;

        access_log /var/log/nginx/site.name/access.log;
        error_log /var/log/nginx/site.name/error.log;

        ssl_certificate /etc/letsencrypt/live/site.name/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/site.name/privkey.pem;
        ssl_trusted_certificate /etc/letsencrypt/live/site.name/chain.pem;

        include ssl_params;

        ssl_stapling on;
        ssl_stapling_verify on;
        resolver 8.8.8.8;

        client_max_body_size 10M;

        include acme;

        location / {
                include proxy_params;
                proxy_pass http://127.0.0.1:42001;
        }
}

server {
        listen 80;
        listen [::]:80;

        server_name site.name;

        return 301 https://$host$request_uri;
}
  • /etc/nginx/proxy_params
proxy_set_header Host $http_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;
  • /etc/nginx/ssl_params
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";

ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;

ssl_dhparam /etc/ssl/private/dhparam.pem;

# исключим возврат на http-версию сайта
add_header Strict-Transport-Security "max-age=31536000";

# явно "сломаем" все картинки с http://
add_header Content-Security-Policy "img-src https: data:; upgrade-insecure-requests";
  • не забываем и про генерацию dhparam
openssl dhparam -out /etc/ssl/private/dhparam.pem 2048
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment