Перейти к содержимому

12. SSL и HTTPS

Иллюстрация к уроку

SSL/TLS — протокол шифрования трафика между клиентом и сервером. HTTPS = HTTP + SSL. Без него браузеры показывают “Не защищено” и поисковики понижают в выдаче.

1. Клиент подключается к серверу
2. Сервер отправляет SSL сертификат (публичный ключ)
3. Клиент проверяет сертификат у CA (Certificate Authority)
4. Handshake — договариваются об алгоритме шифрования
5. Весь трафик зашифрован симметричным ключом
CA (Certificate Authority):
- Let's Encrypt (бесплатный, автоматический)
- DigiCert, Comodo, GlobalSign (платные, для enterprise)

Бесплатные SSL сертификаты для всех. Обновляются автоматически.

Окно терминала
# Установка Certbot (Ubuntu)
sudo apt install certbot python3-certbot-nginx -y
# Получить сертификат для домена
sudo certbot --nginx -d example.com -d www.example.com
# Только получить сертификат (без изменения Nginx)
sudo certbot certonly --nginx -d example.com
# Standalone (без Nginx, для других серверов)
sudo certbot certonly --standalone -d example.com

После получения файлы сохраняются в:

/etc/letsencrypt/live/example.com/
├── fullchain.pem # сертификат + цепочка CA
├── privkey.pem # приватный ключ (держи в секрете!)
├── cert.pem # только сертификат
└── chain.pem # только цепочка CA
Окно терминала
# Wildcard — один сертификат для всех поддоменов
# Требует DNS валидацию
sudo certbot certonly \
--manual \
--preferred-challenges=dns \
-d "*.example.com" \
-d "example.com"
# Certbot попросит добавить TXT запись в DNS:
# _acme-challenge.example.com TXT "xxxxxxxxxxxxx"

Сертификаты Let’s Encrypt действуют 90 дней. Certbot настраивает автообновление через systemd:

Окно терминала
# Проверить статус автообновления
sudo systemctl status certbot.timer
# Тест обновления (dry run)
sudo certbot renew --dry-run
# Принудительное обновление
sudo certbot renew --force-renewal
# Хук после обновления (перезагрузить Nginx)
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
/etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/bin/bash
systemctl reload nginx
Окно терминала
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
/etc/nginx/sites-available/example.com
# HTTP → HTTPS редирект
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# ACME challenge для Certbot
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$server_name$request_uri;
}
}
# HTTPS
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# SSL сертификаты
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# SSL параметры (Mozilla Intermediate рекомендация)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# HSTS (говорим браузеру всегда использовать HTTPS)
add_header Strict-Transport-Security "max-age=63072000" always;
# OCSP Stapling — быстрее валидация сертификата
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 1.1.1.1;
# Session cache
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" always;
location / {
proxy_pass http://localhost:3000;
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;
}
}
Окно терминала
# Создание self-signed (не для production!)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/private/nginx-selfsigned.key \
-out /etc/ssl/certs/nginx-selfsigned.crt \
-subj "/C=RU/ST=Moscow/L=Moscow/O=MyCompany/CN=localhost"
# Использование в Nginx
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
Окно терминала
# Для локальной разработки с HTTPS — лучше использовать mkcert
brew install mkcert
mkcert -install # установить root CA в системе
mkcert localhost 127.0.0.1 ::1
# Создаст:
# localhost+2.pem — сертификат
# localhost+2-key.pem — ключ
# Браузер не будет ругаться!
import https from 'https';
import fs from 'fs';
import express from 'express';
const app = express();
app.get('/', (req, res) => res.send('Hello HTTPS!'));
// Только для разработки — в production лучше Nginx
const options = {
key: fs.readFileSync('./ssl/private.key'),
cert: fs.readFileSync('./ssl/certificate.crt'),
};
https.createServer(options, app).listen(443, () => {
console.log('HTTPS server running on port 443');
});
Окно терминала
# Проверить сертификат
openssl s_client -connect example.com:443 -servername example.com
# Дата истечения
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -dates
# SSL Labs — полная проверка (онлайн)
# https://www.ssllabs.com/ssltest/analyze.html?d=example.com
  • HTTPS обязателен — без него браузеры и поисковики наказывают
  • Let’s Encrypt + Certbot — бесплатные SSL сертификаты с автообновлением
  • Certbot автоматически настраивает Nginx
  • HSTS — говорит браузеру всегда использовать HTTPS
  • Wildcard *.example.com — один сертификат для всех поддоменов
  • Никогда не используй self-signed в production
  • ssl_protocols TLSv1.2 TLSv1.3 — только современные протоколы

Как работает HTTPS — визуализация TLS-рукопожатия: