Все статьи
Руководства

Nginx и Let's Encrypt: бесплатный HTTPS на VPS с Ubuntu и Debian

Коротко

Чтобы сайт на VPS открывался по HTTPS, установите nginx, опишите server block с вашим доменом и proxy_pass на приложение, откройте порты 80 и 443 и выполните sudo certbot --nginx -d example.com. Certbot сам получит бесплатный сертификат Let's Encrypt, настроит редирект на HTTPS и будет продлевать сертификат по таймеру systemd.

Главное
  • Бесплатный HTTPS на VPS получают связкой nginx и certbot: пакеты certbot и python3-certbot-nginx из apt, затем команда sudo certbot --nginx -d example.com -d www.example.com.
  • Nginx работает как reverse proxy: принимает запросы на портах 80 и 443 и через proxy_pass передаёт их приложению на 127.0.0.1:порт, так что само приложение не торчит в интернет.
  • Сертификат Let's Encrypt действует 90 дней, а пакет certbot ставит таймер systemd, который продлевает его автоматически; проверка продления - sudo certbot renew --dry-run.
  • Certbot получит сертификат, только если домен уже указывает на IP сервера и порт 80 открыт снаружи: в UFW это правило sudo ufw allow 'Nginx Full'.

Шаг 1. Установите nginx

Nginx есть в стандартных репозиториях Ubuntu и Debian. После установки служба сразу запускается и включается в автозапуск - статус должен быть active (running):

bash
sudo apt update
sudo apt install -y nginx
systemctl status nginx --no-pager

Шаг 2. Откройте порты 80 и 443 в UFW

Порт 80 нужен для проверки домена Let's Encrypt и редиректа, 443 - для самого HTTPS. Профиль Nginx Full открывает оба:

bash
sudo ufw allow 'Nginx Full'
sudo ufw status

Если UFW ответит, что профиля с таким именем нет (так бывает на Debian), откройте порты напрямую: sudo ufw allow 80,443/tcp. Правило для SSH при этом должно остаться - проверьте его в выводе ufw status.

Шаг 3. Создайте server block для домена

Server block - это описание одного сайта в nginx. Создайте файл /etc/nginx/sites-available/example.com (например, sudo nano /etc/nginx/sites-available/example.com) с таким содержимым - nginx будет принимать запросы на домен и передавать их приложению на 127.0.0.1:3000:

/etc/nginx/sites-available/example.com
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name example.com www.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        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;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}
  • Host передаёт приложению имя домена из запроса - без него приложение увидит 127.0.0.1.
  • X-Real-IP и X-Forwarded-For несут настоящий IP посетителя, иначе в логах приложения все запросы будут от nginx.
  • X-Forwarded-Proto сообщает, пришёл запрос по HTTP или HTTPS: по нему фреймворки строят правильные ссылки и не уходят в цикл редиректов.
  • Upgrade и Connection вместе с блоком map нужны для WebSocket. Блок map объявляется один раз на сервер: для второго сайта копируйте только server.

Шаг 4. Включите сайт и проверьте конфигурацию

Сайт включается ссылкой в sites-enabled. Стандартный сайт-заглушку default удалите, чтобы он не перехватывал запросы. nginx -t проверяет синтаксис до перезагрузки - если он пишет syntax is ok и test is successful, конфигурацию можно применять:

bash
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
curl -I http://example.com

Последняя команда должна вернуть ответ вашего приложения по HTTP. Ответ 502 Bad Gateway значит, что nginx работает, а приложение на порту 3000 не запущено.

Шаг 5. Получите сертификат Let's Encrypt через certbot

Certbot - официальный клиент Let's Encrypt от EFF, плагин python3-certbot-nginx сам правит конфигурацию nginx. Укажите все имена, на которые должен действовать сертификат, флагом -d; --redirect сразу включает перенаправление с HTTP на HTTPS:

bash
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx --redirect -d example.com -d www.example.com

При первом запуске certbot спросит email и попросит принять условия Let's Encrypt. Затем он проверит, что домен ведёт на этот сервер (запрос на порт 80), получит сертификат и допишет в server block строки listen 443 ssl и пути к ключам. Подробнее о параметрах - на certbot.eff.org.

Шаг 6. Проверьте автопродление

Сертификат Let's Encrypt действует 90 дней. Пакет certbot из apt ставит таймер systemd, который дважды в день проверяет сертификаты и продлевает те, срок которых подходит к концу; после продления плагин сам перезагружает nginx. Убедитесь, что продление пройдёт:

bash
sudo certbot renew --dry-run
systemctl list-timers | grep certbot
sudo certbot certificates

--dry-run проходит всю процедуру на тестовом сервере Let's Encrypt, не трогая настоящий сертификат. Вторая команда показывает таймер certbot.timer и время следующего запуска, третья - срок действия выпущенных сертификатов.

Шаг 7. Проверьте HTTPS и редирект

Запрос по HTTP должен вернуть 301 Moved Permanently с адресом https:// в заголовке Location, а запрос по HTTPS - ответ приложения без ошибок сертификата:

bash
curl -I http://example.com
curl -I https://example.com

Частые ошибки certbot и nginx

Что видитеПричинаЧто сделать
DNS problem: NXDOMAIN или проверка уходит на чужой IPDNS ещё не обновился или A-запись указывает не тудаПроверьте dig +short example.com через публичный резолвер и дождитесь, пока он вернёт IP сервера
Timeout during connect (likely firewall problem)Порт 80 закрыт снаружи: правило UFW, nginx не слушает 80 или домен проксируется Cloudflare с ошибкойsudo ufw allow 'Nginx Full', sudo ss -tlnp - nginx должен слушать :80
too many certificates или too many failed authorizationsСработали лимиты Let's Encrypt на число выпусков или неудачных проверокЭксперименты делайте с --dry-run, подождите снятия лимита; актуальные значения - в документации Let's Encrypt
502 Bad GatewayПриложение не запущено или слушает другой портcurl http://127.0.0.1:3000 на сервере; сверьте порт в proxy_pass
conflicting server name в nginx -tОдин домен описан в двух server blockОставьте домен в одном файле в sites-enabled

За nginx удобно прятать любые приложения: Node.js-сервис, вебхук Telegram-бота (Telegram принимает вебхуки только по HTTPS) или контейнеры Docker. Для nginx с парой небольших сайтов хватает конфигурации с 1 vCPU и 2 ГБ памяти; VPS Tihost с полным root-доступом разворачивается примерно за 2 минуты.

Запустите сервер за 2 минуты

AMD Ryzen 9, NVMe и защита от DDoS в Германии, Финляндии и Польше. Оплата криптовалютой или картой.

Заказать сервер

Частые вопросы

Сколько стоит сертификат Let's Encrypt?

Сертификат Let's Encrypt бесплатный: его выпускает некоммерческий центр сертификации, а certbot получает и продлевает его автоматически. Браузеры доверяют ему так же, как платным DV-сертификатам.

Как часто нужно продлевать сертификат Let's Encrypt?

Сертификат Let's Encrypt действует 90 дней, но вручную его продлевать не нужно: таймер systemd из пакета certbot продлевает его заранее. Проверить продление можно командой sudo certbot renew --dry-run.

Почему certbot пишет Timeout during connect?

Let's Encrypt не может достучаться до сервера по порту 80. Откройте порты командой sudo ufw allow 'Nginx Full', проверьте, что nginx запущен, и что домен указывает на IP этого сервера.

Можно ли получить сертификат на IP-адрес без домена?

Для обычной схемы с certbot и nginx нужен домен: сертификат выпускается на имя, которое указывает на сервер. Домен можно купить у любого регистратора и привязать A-записью за несколько минут.

Чем certbot из apt отличается от certbot из snap?

Сайт certbot.eff.org рекомендует snap, где certbot обновляется быстрее. Пакеты certbot и python3-certbot-nginx из apt в Ubuntu и Debian тоже работают и обновляются вместе с системой - для одного сайта разницы нет.

Что такое reverse proxy в nginx?

Reverse proxy - сервер, который принимает запросы из интернета и передаёт их приложению внутри сервера. В nginx за это отвечает директива proxy_pass http://127.0.0.1:3000;, а nginx при этом берёт на себя HTTPS, сжатие и статику.