Архив метки: ssl

NGINX установка и настройка

Установим и настроим Nginx на системе Rocky Linuxи или любого дистрибутива семейства RHEL. Рассмотрим разные варианты использования сервиса. Использование Nginx для web проектов работающих на бюджетных хостингах или железе — лучший вариант.

Введение

Из этой статьи вы узнаете про основные моменты работы с Nginx на системах CentOS, Rocky Linux и любого дистрибутива семейства любое семейство RHEL. Более подробно о работе с Nginx можно узнать на сайте разработчика в разделе документации. Долгое время лидирующие позиции занимал Apach, но новый продукт кардинально изменил подход к обработке команд и позволяет обслуживать высоко нагруженные сайты на бюджетном железе. Более детально узнать про автора Игоря Сысоева и ознакомится с принципами работы вы можете на просторах сети интернет. От себя лишь скажу что теперь это моя основная и любимая связка при организации веб сервера по причине быстроты и удобства работы.

Установка NGINX

Для установки будем использовать репозиторий разработчика NGINX.

Для установки самой свежей стабильной версии Nginx на СentOS или Rocky Linux (любое семейство RHEL) подключим родной репозиторий выполнив следующие действия:

= Установим необходимую зависимость =
dnf install yum-utils

= Создадим файл с репозиторием и обновим систему = 
vim /etc/yum.repos.d/nginx.repo
=== Необходимый код для внесения ===
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

= Обновим систему =
dnf update

Установим выполнив команду:

dnf install nginx

Перед установкой убеждаемся что установка идет с репозитория nginx.

Запустим и добавим в автозагрузку:

systemctl start nginx
systemctl enable nginx

= Можно одной командой =
systemctl enable --now nginx

Для проверки выполним команду в консоли:

curl http://localhost
= вывод команды =
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Видим код страницы. NGINX работает.

Например, мне не удобно видеть такую страницу по умолчанию и я привожу её к следующему виду:

vim /usr/share/nginx/html/index.html
= необходимый код =
<!DOCTYPE html>
<html>
<head>
<title>Welcome!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working.</p>

<p><em>lemp.sevo44.loc</em></p>
</body>
</html>

Используя такую страницу я всегда понимаю на какой сервер я попадаю.

Настройка NGINX

Вся прелесть настройки сводится к тому что вы всегда можете проверить правильность своих настроек выполнив команду:

nginx -t

Варианты конфигурации для сайтов

Дальше надо определится как будем работать с настройкой сайтов.
Существует два пути:

  • редактирование всё в одном файле;
  • для каждого сайта сделать свой файл настроек.

Например, лично мне нравится для каждого сайта создавать свой конфигурационный файл. В статье будет описан именно этот способ.

Главный конфигурационный файл

Переименуем оригинальный конфигурационный фал Nginx и создадим новый внеся необходимый код:

mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf_orig
vim /etc/nginx/nginx.conf
= необходимый код =
user nginx;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 30000;
pid /var/run/nginx.pid;
pcre_jit on;

events {
worker_connections 8192;
multi_accept on;
}

http {
# Basic #######################
sendfile on;
tcp_nopush on;
tcp_nodelay on;
reset_timedout_connection on;
keepalive_timeout 120;
keepalive_requests 1000;
types_hash_max_size 2048;
server_tokens off;
send_timeout 30;
client_body_timeout 30;
client_header_timeout 30;
server_names_hash_max_size 4096;

# Limits ######################
client_max_body_size 10m;
client_body_buffer_size 128k;
client_body_temp_path /var/cache/nginx/client_temp;

proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffer_size 4k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_temp_path /var/cache/nginx/proxy_temp;

include /etc/nginx/mime.types;
default_type application/octet-stream;

# Logs ########################
log_format main '$remote_addr - $host [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'rt=$request_time ut=$upstream_response_time '
'cs=$upstream_cache_status';
log_format full '$remote_addr - $host [$time_local] "$request" '
'request_length=$request_length '
'status=$status bytes_sent=$bytes_sent '
'body_bytes_sent=$body_bytes_sent '
'referer=$http_referer '
'user_agent="$http_user_agent" '
'upstream_status=$upstream_status '
'request_time=$request_time '
'upstream_response_time=$upstream_response_time '
'upstream_connect_time=$upstream_connect_time '
'upstream_header_time=$upstream_header_time';

access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log;

# Gzip ########################
gzip on; 
gzip_static on; 
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/x-icon image/svg+xml application/x-font-ttf;
gzip_comp_level 9;
gzip_proxied any;
gzip_min_length 1000;
gzip_disable "msie6";
gzip_vary on;

etag off;

# Cache #######################
#proxy_cache_valid 1m;
#proxy_cache_key $scheme$proxy_host$request_uri$cookie_US;
#proxy_cache_path /web/sites/nginx_cache levels=1:2 keys_zone=main:1000m;

# Zone limits ################
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_req_zone $binary_remote_addr zone=lim_5r:10m rate=5r/s; # lim for dynamic page
limit_req_zone $binary_remote_addr zone=lim_1r:10m rate=1r/s; # lim for search page
limit_req_zone $binary_remote_addr zone=lim_10r:10m rate=10r/s;

# SSL #########################
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets on;
ssl_protocols TLSv1.2 TLSv1.3;
#ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-256-GCM-SHA384:ECDHE:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security max-age=15768000;
resolver 8.8.8.8;

include /etc/nginx/conf.d/*.conf;

# For monitoring ###########
#server {
#listen 127.0.0.1:80;
#server_name status.localhost;
#keepalive_timeout 0;
#allow 127.0.0.1;
#deny all;
#access_log off;

#location /server-status {
#stub_status on;
#}

#location /status {
#access_log off;
#allow 127.0.0.1;
#deny all;
#include fastcgi_params;
#fastcgi_pass unix:/run/php-fpm/www.sock;
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
#}
#}
}

Это мой базовый вариант который подходит практически для всех моих ресурсов где необходимо настраивать Nginx.

Конфигурации Nginx для сайтов

Связка c PHP осуществляется с использованием php-fpm. Узнать более подробно можно из статьи PHP от Remi для CentOS 7.

Рассмотрим на примере конфигурации для сайта на котором работает phpMyAdmin. Конфигурационный файл выглядит следующим образом:

#pma.sevo44.loc
server {
listen 80;
server_name pma.sevo44.loc www.pma.sevo44.loc;

access_log /var/www/pma.sevo44.loc/log/pma.sevo44.loc-access_log main;
error_log /var/www/pma.sevo44.loc/log/pma.sevo44.loc-error_log info;

root /var/www/pma.sevo44.loc/www/;
index index.php;

location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm/php-fpm.socket;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_intercept_errors on;
fastcgi_ignore_client_abort off;
fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
}
}

Запросы на ресурс будут осуществятся с проксирующего сервира Nginx. О том как перевести ресурс на работу по https вы узнаете ниже.

Доступ по IP адресу

Бывают случаи когда необходимо помимо домена попадать на ресурс по ip адресу и для этого достаточно добавить один параметр в файл настройки для ресурса.

= часть кода с примером =
server { 
listen 80 default_server; 
server_name pma.sevo44.loc www.pma.sevo44.loc;

Доступ к ресурсу по паролю

Иногда для безопасности необходимо закрыть ресурс на пароль. Сделаем это средствами Nginx используя механизм basic auth.

Добавим в секцию server необходимого сайта код:

= необходимый код =
### Авторизация по паролю используя basic auth
auth_basic "Restricted Content";
auth_basic_user_file /etc/nginx/.htpasswd;

Создаем файл с логином и паролем для доступа:

=== Команда которая создаст пользователя pma ===
sh -c "echo -n 'pma:' >> /etc/nginx/.htpasswd"

=== Команда для создания пароля пользователю pma ===
sh -c "openssl passwd -apr1 >> /etc/nginx/.htpasswd"

= Вывод команды с пояснениями =
Password: пароль
Verifying - Password: повтор пароля

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

cat /etc/nginx/.htpasswd 
= вывод команды =
pma:$apr1$7xGrtwfB$fZNKV9J5fjr%fbvfMuhPvSFS0

Можно добавлять любое количество пользователей меняя только имя создаваемого пользователя.

Для смены текущего пароля пользователя достаточно выполнить команду по созданию пароля без добавления пользователя а потом зайти в файл и последнюю строчку вида $apr1$7xG6owfB$fZNKV9J5gjjj^YfMuhPvSFSв заменить пользователю которому меняем пароль.

После обновления конфигурации Nginx при попытке зайти на ресурс мы увидим простую форму где необходимо внести наши данные.

Параметры php для сайта

На одном сервере может быть разное количество сайтов которые используют одну версию php, но для каждого нужны своим определённые параметры. С решением этой задачи легко справляется Nginx. Например, я не редактирую базовый файл с настройками версии php а для каждого ресурса создаю свои персональные настройки. Кроме того, иногда нет возможно подправить базовый файл так чтобы он удовлетворял условиям всех сайтов.

Для просмотра действующих параметров php необходимо создать файл на требуемом ресурсе и добавить туда следующий код:

vim info.php
= необходимый код =
<?php
phpinfo();
?>

Теперь с учетом того что файл создали в корне сайте необходимо открыть его https://ваш домен/info.php и увидеть все реально действующие параметры для данного ресурса.

Смотрим те параметры что нам надо и добавляем их по аналогии к существующим в коде ниже.

Значения для параметров которые возможны всегда можно посмотреть в комментариях базового файла php.ini

Вот так добавив требуемый код в необходимый блок я задал свои параметры для размера загружаемых файлов и выставил необходимую локализацию:

location ~ \.php$ {
fastcgi_pass unix:/var/opt/remi/php80/run/php-fpm/sevo44.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_param HTTPS on;
fastcgi_param PHP_VALUE "
# max_execution_time = 300
# short_open_tag = On
post_max_size = 12M
upload_max_filesize = 12M
# max_input_time = 300
date.timezone = Europe/Moscow
";
}

После необходимых изменений проверяем правильность кода и в случае успеха перегружаем Nginx:

nginx -t
= вывод команды =
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

nginx -s reload

При переходе с одной версии php на другую этот вариант очень актуален. В новой версии могут меняться некоторые параметры и их с легкостью можно применить в этом файле.

Команды управления

Обновление параметров без перезагрузки сервиса (рекомендуемый вариант):

nginx -s reload
= или =
systemctl reload nginx

Полная перезагрузка сервиса

systemctl restart nginx

Остановка и запуск соответственно:

systemctl stop nginx
systemctl start nginx

Проксирования запросов на удаленный сервер

В локальной сети может работать множество сайтов. Самый лучший способ это настроить одну точку входа и оттуда переправлять запросы на ресурсы в локальной сети. Nginx прекрасно с этим справляется используя модуль ngx_http_proxy_module. Более подробно о том как можно настраивать проксирование запросов вы можете в документации разработчика.

Мне нравится использовать эту технологию так как она позволяет:

  • Работа всех ресурсов по https. На проксирующем сервере мы получаем сертификаты для всех ресурсов а перенапровление запросов идет по http. Контролировать получение сертификатов SSL в одном месте для всех сайтов локальной сети очень удобно;
  • Смена мест размещения ресурсов. Перевозить сервер на новое место не вызывает проблем. Достаточно настроить сайт на новом месте а потом просто поменять ip адресс на проксирующем Nginx.
  • Проксирование папок или фалов. Для оптимизации работы ресурса можно распределять нагрузку на разные ресурсы. Например, перенести загрузку определенных фалов (фотографии) или папок на другие сервера.

Для примера, так же будем использовать проксирование запросов для phpMyAdmin.

Параметры в используемом примере следующие:

  • pma.sevo44.ru — домен ресурса;
  • 10.10.0.1 — ip адрес ресурса с которого пересылается запрос. Проксирующий сервер работает на сервера в котором проксирование проходит на контейнеры LXC которые работают в своей сети 10.10.0.0/24;
  • 10.10.0.4 — ip ресурса на который происходит проксирование сигналов.

Настройка на проксирующем Nginx

Прежде всего, обычно я создаю конфигурационный файл в котором присутствует весь код, но секции отвечающие за работу ресурса на https комментированы.

Из приведенного примера ниже вы узнаете:

  • Как осуществлять редирект с http на https;
  • Включение сжатия GZIP для ресурса;
  • Настройки для работы https. Узнать более подробно о том как получать сертификат SSl можно из статьи «SSL бесплатный для сайта Nginx«;
  • Работа ресурса по http2;
  • Команды переправляющие ip адрес для правильного отображения в логах;
  • Настройка размера файлов которые можно загружать на проксируемый ресурс;
  • Папка которая будет использована для получения сертификата ssl.
### ssl pma.sevo44.ru
### Перенаправление с http на https
#server {
#listen 80;
#server_name pma.sevo44.ru www.pma.sevo44.ru;
#rewrite ^ https://$server_name$request_uri? permanent;
#}
server {
### Перевод работы ресурса на https c http2
#listen 443 ssl http2;
listen 80;
server_name pma.sevo44.ru www.pma.sevo44.ru;
### Включение сжатия GZIP
### Если используется NGINX proxy надо настраивать на нём!!!
#gzip on;
#gzip_static on;
#gzip_types text/plain text/css application/json application/x-#javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/x-icon image/svg+xml application/x-font-ttf;
#gzip_comp_level 6;
#gzip_proxied any;
#gzip_min_length 1000;
#gzip_disable "msie6";
#gzip_vary on;
### ssl
#ssl on;
#ssl_certificate /etc/letsencrypt/live/pma.sevo44.ru/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/pma.sevo44.ru/privkey.pem;
#ssl_session_timeout 5m;
#ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#ssl_dhparam /etc/letsencrypt/dhparam.pem;
#ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
#ssl_prefer_server_ciphers on;
#ssl_session_cache shared:SSL:10m;
### Папка используемая для получения сертификата ssl
location /.well-known/acme-challenge/ {
root /var/www/ssl/pma.sevo44.ru/;
}
location / {
### Ip адрес проксируемого ресурса
proxy_pass http://10.10.0.4:80;
### Настройки для передачи в логи проксируемых ресурсов реальных ip
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
### Код для указания размера максимальной зугрузки файлов 10 M
### так же нужна строчка в файле настройки сайта
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 6000;
proxy_read_timeout 6000;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
}

Настройка на проксируемом ресурсе

Исходя из настроек на проксируещем сервере конфурационный файл проксируемого ресурса имеет следующий вид:

### pma.sevo44.ru
server {
listen 80;
server_name pma.sevo44.ru www.pma.sevo44.ru;

access_log /usr/share/phpMyAdmin/log/pma.sevo44.ru-access_log main;
error_log /usr/share/phpMyAdmin/log/pma.sevo44.ru-error_log info;

root /usr/share/phpMyAdmin/;
index index.php;

### Для записи в log реальных ip
set_real_ip_from 10.10.0.1;
real_ip_header X-Real-IP;

location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param HTTPS on;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_intercept_errors on;
fastcgi_ignore_client_abort off;
fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
} 
}

Проксирование директории или файлов

Секции должны входить в блок server.

Например, проксируем папку foto находящуюся на другом ресурсе:

location /foto/ {
proxy_pass http://192.168.0.200:80; 
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect default;
}

Для проксирования файлов с форматом gif,jpg,png код будет иметь следующий вид:

location / {
proxy_pass http://192.168.0.200:80; 
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}

location ~ \.(gif|jpg|png)$ { 
root /web/sites/blog.zeroxzed.ru/www/images; 
}

Вывод

Каждый ресурс индивидуален. В статье приведены только самые основы и для того чтобы настроить работу ресурса максимально оптимально для работы вам придется используя документацию разработчика. Особое внимание следует уделить директивам кэширования proxy_cache так как они очень сильно могут влиять на скорость работы ресурса.

SSL бесплатный для сайта Nginx

Получим и настроим автоматическое обновление бесплатного сертификата SSL для сайта от компании  Lets`Encrypt. Срок сертификата 90 дней. Настроить получение сертификатов возможно на любой операционной системе Linux. Стабильная и удобная работа с сервисом.

Введение

С января 2017 года Firefox и Chrome маркируют как надежные только сайты с SSL-сертификатами. Это одна из причин по которой следует использовать этот сертификат.

Если коротко, то это защита сайта которая многим не нужна, но введение некоторых ограничений заставляет использовать её. Хорошо что есть ресурсы которые предоставляют сертификаты бесплатно, сколько времени еще так будет не известно, но мы пока попользуемся.

Мной было найдено два ресурса выдающие бесплатные SSL для сайтов:

  • StartCom — у этого ресурса проблемы с разработчиками браузеров и чем все это закончится не понятно. Удобно что выдается на 3 года и можно установить на любой обычный хостинг.
  • Let’s Encrypt is — все работает и никаких проблем нет. Для установки нужен свой VDS хостинг. Хоть сертификат и выдается на 90 дней, но при настройке автоматического обновления никаких проблем не возникает.

Мой выбор однозначно пал на второй вариант, так как стабильность и понятность для меня самое важное.

Подробно про установку и начальную настройку сервера вы можете узнать в моей статье Rocky Linux 8 установка и настройка.

Установка Certbot от Let’s Encrypt

На сайте компании есть инструкция об установке и использованию. По ссылке вы можете увидеть инструкцию для установки SSL на Nginx под управлением CentOS 8 = Rocky Linux 8. Можете указать свои системы и получить инструкцию для них.

Разработчик рекомендует использовать пакетную систему Snap. Ее смысл заключается в том, что в пакет с приложением входит полный набор компонентов, необходимых для запуска данного приложения. Такие пакеты можно устанавливать в систему не заботясь о зависимостях, так как все зависимости уже включены в пакет. Пакетная система Snap была созданная компанией Canonical и изначально появилась в дистрибутиве Ubuntu Linux.

При установке на дистрибутивы которые используют не стабильные репозитории это очень оправдано и понятно почему. В нашем случае устанавливать в таком виде не имеет смысла. Лично у меня на протяжении лет 5 проблем не возникало.

Для использования Certbot, необходимо сначала добавить репозиторий Epel . Подключим необходимый репозиторий:

dnf -y install epel-release

Установим без вопросов Certbot от Let’s Encrypt:

yum -y install certbot

Предварительная подготовка

Предварительная подготовка заключается в выполнении двух действий:

  1. Ответы на вопросы от разработчика;
  2. Вносим необходимые настройки в конфигурацию Nginx.

Подробно про установку и начальную настройку сервера вы можете узнать в моей статье NGINX установка и настройка.

Ответы на вопросы от разработчика

Запускаем получение сертификата, но получать его не будем. Необходимо ответить на несколько вопросов от разработчика:

certbot certonly
= вывод команды =
Saving debug log to /var/log/letsencrypt/letsencrypt.log

How would you like to authenticate with the ACME CA?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Spin up a temporary webserver (standalone)
2: Place files in webroot directory (webroot)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Enter email address (used for urgent renewal and security notices)
= в случае проблем с получением сертификата на эту почту будут приходить сообщения =
= можно указать выдуманный =
(Enter 'c' to cancel): info@sevo44.ru

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
= подтверждаем что ознакомились с условиями предоставления услуг =
(Y)es/(N)o: Y

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
= Просят поделиться своим адресом электронной почты с Фондом Electronic Frontier,
партнером-основателем проекта Let's Encrypt и некоммерческой организацией, которая
разрабатывает Certbot. Отказываюсь. =
(Y)es/(N)o: N
Account registered.

= Выходим по Ctrl + C =

В данном примере есть два варианта получения сертификата. Расскажу грубо о каждом варианте и поясню разницу:

  1. Spin up a temporary webserver (standalone) — при таком варианте сертификат будет получен с использованием тестового сервера разработчика. Этот вариант подходит при условии что сайт уже где то работает и нам его надо перенести. После переезда нам надо заходить в настройки получения сертификата и менять параметры. Мне такой вариант не нравится и ниже вы узнаете почему;
  2. Place files in webroot directory (webroot) — при этом варианте сервис проверяет доступ к серверу и если он есть выдает сертификат. Основное преимущество данного вида в том что мне не надо в последствии править настройки получения сертификата. Достаточно с работающего сервера взять действующие сертификаты положить их в свое место и прописать пути в настройках Nginx. После реального переезда сайта достаточно получить сертификаты и указать в настройках Nginx новые пути.

Вносим необходимые настройки в конфигурацию Nginx

В конфигурации Nginx для сайта должны быть добавлены следующие строки:

location /.well-known/acme-challenge/ {
root /etc/nginx/cert-renewal/;
}

Создадим необходимую папку:

mkdir /etc/nginx/cert-renewal/

Можно для каждого сайта указывать свою директорию, но мне это не нравится. Предпочитаю делать общую.

При настройке Nginx для работы сайтов с использованием сертификатов есть два варианта:

  1. Внести все основные настройки для работы сайта с сертификатом в главный файл настройки Nginx а в настройках для самого сайта указывать только пути для сертификата;
  2. Не трогать главный файл и все настройки прописывать в настройках для сайта.

Лично я предпочитаю первый вариант и именно он будет описан ниже.

Вот пример моего файла настроек главного конфигурационного файла Nginx:

cat /etc/nginx/nginx.conf
= вывод команды =
user nginx;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 30000;
pid /var/run/nginx.pid;
pcre_jit on;

events {
worker_connections 8192;
multi_accept on;
}

http {
# Basic #######################
sendfile on;
tcp_nopush on;
tcp_nodelay on;
reset_timedout_connection on;
keepalive_timeout 120;
keepalive_requests 1000;
types_hash_max_size 2048;
server_tokens off;
send_timeout 30;
client_body_timeout 30;
client_header_timeout 30;
server_names_hash_max_size 4096;

# Limits ######################
client_max_body_size 10m;
client_body_buffer_size 128k;
client_body_temp_path /var/cache/nginx/client_temp;

proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffer_size 4k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_temp_path /var/cache/nginx/proxy_temp;

include /etc/nginx/mime.types;
default_type application/octet-stream;

# Logs ########################
log_format main '$remote_addr - $host [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'rt=$request_time ut=$upstream_response_time '
'cs=$upstream_cache_status';
log_format full '$remote_addr - $host [$time_local] "$request" '
'request_length=$request_length '
'status=$status bytes_sent=$bytes_sent '
'body_bytes_sent=$body_bytes_sent '
'referer=$http_referer '
'user_agent="$http_user_agent" '
'upstream_status=$upstream_status '
'request_time=$request_time '
'upstream_response_time=$upstream_response_time '
'upstream_connect_time=$upstream_connect_time '
'upstream_header_time=$upstream_header_time';

access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log;

# Gzip ########################
gzip on; 
gzip_static on; 
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/x-icon image/svg+xml application/x-font-ttf;
gzip_comp_level 9;
gzip_proxied any;
gzip_min_length 1000;
gzip_disable "msie6";
gzip_vary on;

etag off;

# Cache #######################
#proxy_cache_valid 1m;
#proxy_cache_key $scheme$proxy_host$request_uri$cookie_US;
#proxy_cache_path /web/sites/nginx_cache levels=1:2 keys_zone=main:1000m;

# Zone limits ################
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_req_zone $binary_remote_addr zone=lim_5r:10m rate=5r/s; # lim for dynamic page
limit_req_zone $binary_remote_addr zone=lim_1r:10m rate=1r/s; # lim for search page
limit_req_zone $binary_remote_addr zone=lim_10r:10m rate=10r/s;

# SSL #########################
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets on;
ssl_protocols TLSv1.2 TLSv1.3;
#ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-256-GCM-SHA384:ECDHE:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security max-age=15768000;
resolver 8.8.8.8;

include /etc/nginx/conf.d/*.conf;

# For monitoring ###########

server {
listen 127.0.0.1:80;
server_name status.localhost;
keepalive_timeout 0;
allow 127.0.0.1;
deny all;
access_log off;

location /server-status {
stub_status on;
}

location /status {
access_log off;
allow 127.0.0.1;
deny all;
include fastcgi_params;
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
}

В случае отсутствия /etc/ssl/certs/dhparam.pem генерируем  ключ необходимый для настройки:

openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Процесс не быстрый. Ждите.

Получение бесплатного SSL-сертификата

Приведем к такому виду файл конфигурации сайта перед получением сертификата:

### ssl sevo44.ru
#server {
#listen 80;
#server_name sevo44.ru;
#return 301 https://$server_name$request_uri; # редирект обычных запросов на https
#}

server {
#listen 443 ssl http2;
listen 80;
server_name sevo44.ru;

### ssl
#ssl_certificate /etc/letsencrypt/live/sevo44.ru/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/sevo44.ru/privkey.pem;

location /.well-known/acme-challenge/ {
root /etc/nginx/cert-renewal/;
}

location / {
proxy_pass http://192.168.0.112:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#client_max_body_size 10m;
#client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 6000;
proxy_read_timeout 6000;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
}

В этом файле два блока server. Первый отвечающий за работы http мы закомментировали, второй отвечающий за https перевели на работу по http и закомментировали пути к сертификату.

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

nginx -t
= вывод при успешной настройке =
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

nginx -s reload

Все предварительные подготовки сделаны. Переходим к непосредственному получению сертификата.

Не знаю какие ограничения на установку, но я спокойно установил SSL сертификат на домен и 5 его поддоменов.

Пример получения сертификата SSL:

certbot certonly
= вывод команды с действиями =
Saving debug log to /var/log/letsencrypt/letsencrypt.log

How would you like to authenticate with the ACME CA?
-------------------------------------------------------------------------------
1: Spin up a temporary webserver (standalone)
2: Place files in webroot directory (webroot)
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Please enter in your domain name(s) (comma and/or space separated) (Enter 'c'
to cancel):sevo44.ru
Requesting a certificate for sevo44.ru
Input the webroot for sevo44.ru: (Enter 'c' to cancel):/etc/nginx/cert-renewal
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /etc/letsencrypt/keys/0014_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0014_csr-certbot.pem

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
 /etc/letsencrypt/live/sevo44.ru/fullchain.pem. Your cert will
 expire on 2021-12-14. To obtain a new or tweaked version of this
 certificate in the future, simply run certbot again. To
 non-interactively renew *all* of your certificates, run "certbot
 renew"
 - 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

Сертификат успешно получен и указан период его действия.

Получение одного сертификата на домен с WWW и без

При попытке зайти по ссылке https://www.sevo44.ru мы получим сообщение об ошибке сертификата:

curl -I https://www.sevo44.ru
= вывод команды =
curl: (51) SSL: no alternative certificate subject name matches target host name 'www.sevo44.ru'

В настройках DNS для домена обязательно должен быть прописаны параметры его работы по адресу www.sevo44.ru!

Для исправление этой ошибки необходимо получить сертификат на домен с www и без.

Команда выглядит следующим образом:

certbot certonly --webroot --expand -d sevo44.ru -d www.sevo44.ru

Где параметры имеют следующие значения:

  • certbot certonly — команда на получение сертификата;
  • webroot — способ получения сертификата;
  • expand — ключ для получения на один сертификат несколько доменов.

После успешного получения выполняется проверка следующей командой:

curl -I https://www.sevo44.ru
= вывод команды =
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Tue, 06 Aug 2019 20:26:56 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/7.2.20
Vary: Accept-Encoding, Cookie
X-Redirect-By: WordPress
Location: https://sevo44.ru/

Ошибок больше нет.

Установка SSL-сертификата на сайт c Nginx

Вся установка сертификата на сайте под управлением Nginx заключается в правке файла настройки виртуального хоста.

Все полученные сертификаты будут лежать в папке /etc/letsencrypt/live/ согласно доменным именам вводимым при получении.

Приведем к такому виду файл конфигурации сайта после получением сертификата:

### ssl sevo44.ru 
server { 
listen 80; 
server_name sevo44.ru; 
return 301 https://$server_name$request_uri; # редирект обычных запросов на https 
}

server { 
listen 443 ssl http2;
#listen 80;
server_name sevo44.ru;

### ssl 
ssl_certificate /etc/letsencrypt/live/sevo44.ru/fullchain.pem; 
ssl_certificate_key /etc/letsencrypt/live/sevo44.ru/privkey.pem;

location /.well-known/acme-challenge/ {
root /etc/nginx/cert-renewal/;
}

location / {
proxy_pass http://192.168.0.112:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#client_max_body_size 10m;
#client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 6000;
proxy_read_timeout 6000;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
}

Мы разкоментировали все строчки что ранее закомментировали и переключили второй блок на работу по https с указанием путей к сертификатам. Как вы заметил http2 протокол включается простым добавлением этой записи.

Сделаем проверку настроек и обновим настройки Nginx:

nginx -t
nginx -s reload

Ресурсы проверки SSL и Http2 сайта

Проверим сторонними ресурсами как установился наш SSL-сертификат.

  • SSLChecker — cервис проверки настройки SSL,
  • SSLReport — сервис проверки SSL но более детальный.

Проверим работу http2 протокола:

  • HTTP/2 Test — сервис показывающий проверяющий работу http2.

Продление SSL-сертификата

Есть возможность производить обновления в ручную и в автоматическом режиме.

Ручной режим

Проверим автоматическое продление сертификатов, выполнив эту команду:

certbot renew --dry-run
= вывод команды =
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/sevo44.ru.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator webroot, Installer None
Simulating renewal of an existing certificate for sevo44.ru
Performing the following challenges:
http-01 challenge for sevo44.ru
Waiting for verification...
Cleaning up challenges

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/sevo44.ru/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/sevo44.ru/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Видим что все хорошо.

Для обновления всех сертификатов достаточно запустить команду:

certbot renew 
= вывод команды =
Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/sevo44.ru.conf
-------------------------------------------------------------------------------
Cert not yet due for renewal

The following certs are not due for renewal yet:
 /etc/letsencrypt/live/sevo44.ru/fullchain.pem (skipped)
No renewals were attempted.

Обновлять ничего.

Автоматический режим

Для автоматического обновления нам необходимо добавить параметры в crontab:

vim /etc/crontab
= необходимое варианты добавление =
# Cert Renewal
# запись в лог файл
30 2 0 * * root /usr/bin/certbot renew --post-hook "nginx -s reload" >> /var/log/letsencrypt/cron-renew.log

=== или ===
# без записи в лог файл
30 2 0 * * root /usr/bin/certbot renew --post-hook "nginx -s reload" >> /dev/null 2>&1

Согласно этой настройке команда будет выполняться по воскресеньям в 2:30 после выполнения произойдёт reload nginx.

Удаление сертификата

Удаление сертификата состоит из двух частей:

  1. Аннулирование сертификатов на серверах Let`s Enscrypt;
  2. Удаление сертификатов на сервере.

Аннулируем сертификат:

certbot revoke --cert-path /etc/letsencrypt/archive/sevo44.ru/cert1.pem
= вывод команды =
Saving debug log to /var/log/letsencrypt/letsencrypt.log
An unexpected error occurred:
The client lacks sufficient authorization :: Certificate is expired
Please see the logfiles in /var/log/letsencrypt for more details.

В выводе говориться что сертификат просрочен и удалять нечего.

Удалим сертификат на сервере:

certbot delete --cert-name sevo44.ru
= вывод команды =
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The following certificate(s) are selected for deletion:

* sevo44.ru

Are you sure you want to delete the above certificate(s)?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y - подтверждаем удаление
Deleted all files relating to certificate sevo44.ru.

Принудительное обновление сертификата

Бывает ситуации когда надо принудительно обновить сертификат по разным причинам.

Вот варианты команд которые можно использовать:

= Для принудительного обновления всех сертификатов =
certbot --force-renewal

= Выборочное принудительное обновление сертификатов =
= через запятую указываются все необходимые доменные имена =
certbot --force-renewal -d www.itsecforu.ru,itsecforu.ru

Заключение

Не сразу я пришел к такому механизму настройки получения сертификатов. Мне кажется такой вариант удобен и понятен. Использую эту инструкцию на рабочих серверах. Проблем с автоматическим обновлением сертификатов и программы не возникало.

Если захочется посмотреть более подробно инструкцию выполните команду:

certbot --help

certbot --help all
Например можете отфильтруйте опцию обновления, используя команду grep / egrep:
certbot --help all | grep -i force
certbot --help all | egrep -i 'renewal|force'