Короткий ответ

Не крутите systemctl restart nginx, пока nginx -t не зелёный. Сначала синтаксис и пути к сертификатам, затем кто слушает 80/443 на 10.0.20.40. Частые причины: опечатка в server_name, include на удалённый файл, ssl_certificate указывает на пустой путь после сбоя certbot, Apache уже занял порт. Хост сайта — site.example, корень /var/www/site.example.

nginx -t читает конфиг от имени процесса; если тест проходит, а unit падает — смотрите journalctl -u nginx и ss -tlnp. Не удаляйте /etc/nginx «чтобы поставить заново».

Симптомы и как отличить

Типичная картина:

  • systemctl is-active nginx = failed или inactive;
  • сайт не открывается, curl -I http://10.0.20.40 даёт connection refused;
  • в журнале nginx.service: Failed with result 'exit-code'.

Отличия:

Что видноЭто не «nginx лёг»Куда
Unit active, сайт 502upstream мёртв502 Bad Gateway
Unit active, 403root/права403 Forbidden
Apache слушает 80, nginx failed bindконфликт пакетовApache не запускается
cannot load certificateTLS-файлыLet's Encrypt

Возможные причины

От частых к редким:

  1. Синтаксическая ошибка в /etc/nginx/sites-enabled/ после ручной правки.
  2. listen 80 или listen 443 ssl — порт уже занят Apache, другим nginx, Docker или NPM.
  3. ssl_certificate / ssl_certificate_key указывают на несуществующий файл (certbot не выпустил, live-каталог пуст).
  4. Права: ключ privkey.pem недоступен пользователю www-data/nginx из‑за слишком закрытого каталога — реже, обычно читает root при старте.
  5. Дублирующий default_server и конфликт server_name.
  6. Модуль в load_module отсутствует в пакете Ubuntu.
  7. Диск заполнен — pid/лог не пишется, unit падает после fork.

Диагностика

Плейсхолдеры: site.example, 10.0.20.40, webroot /var/www/site.example.

1. Тест конфига, не рестарт

sudo nginx -t
sudo nginx -T 2>/dev/null | grep -E 'server_name|listen |ssl_certificate|root ' | head -n 80
systemctl status nginx --no-pager
journalctl -u nginx -n 80 --no-pager

Разбирайте первую строку [emerg]: она указывает файл и номер строки. Исправляйте её, не «комментируйте всё подряд».

2. Кто держит 80 и 443

sudo ss -tlnp | grep -E ':80|:443'
sudo lsof -iTCP:80 -sTCP:LISTEN
sudo lsof -iTCP:443 -sTCP:LISTEN
dpkg -l nginx apache2 | grep ^ii

Если apache2 слушает :80, nginx с listen 80 получит (98: Address already in use). Это не «битый nginx».

3. Сертификаты, на которые ссылается vhost

sudo grep -R ssl_certificate /etc/nginx/sites-enabled /etc/nginx/conf.d
sudo ls -l /etc/letsencrypt/live/site.example/
sudo openssl x509 -in /etc/letsencrypt/live/site.example/fullchain.pem -noout -dates -subject

Пустой live/ после неудачного certbot — типичный [emerg] cannot load certificate. Не запускайте certbot --force-renewal, пока не поняли, почему выпуск сорвался: продление.

4. Include и битые симлинки

ls -l /etc/nginx/sites-enabled/
readlink -f /etc/nginx/sites-enabled/*
sudo nginx -T 2>&1 | grep 'No such file'

sites-enabled/site.example → удалённый sites-available даёт emerg при старте.

5. Диск и pid

df -h / /var
ls -l /run/nginx.pid /var/log/nginx/

Решение

Перед правкой:

sudo tar -C /etc -czf /root/nginx-etc-$(date +%F).tar.gz nginx

Сценарий A. nginx -t красный

Откройте файл из сообщения. Частые опечатки: лишняя } , забытая ;, proxy_pass http://127.0.0.1:3000 без upstream при least_conn. Исправьте одну ошибку, снова nginx -t. Когда тест OK:

sudo systemctl start nginx
sudo systemctl enable nginx

Сценарий B. Порт занят Apache

Либо остановите Apache, если сайт должен жить на nginx, либо уберите listen 80 у nginx, если Apache — фронт. Не держите оба на одном IP:порту.

sudo systemctl stop apache2
sudo systemctl disable apache2
sudo nginx -t && sudo systemctl start nginx

Если Apache нужен для другого vhost — разведите IP или порт, не «убивайте» его без заявки.

Сценарий C. Нет файла сертификата, а listen 443 ssl уже в конфиге

Временно слушайте только 80 или уберите ssl-server до выпуска сертификата. Затем штатный certbot:

sudo certbot certonly --webroot -w /var/www/site.example -d site.example -d www.site.example

В ssl_certificate должен быть fullchain.pem, в ключе — privkey.pem. После появления файлов снова nginx -t и reload.

Минимальный каркас HTTP для выпуска, если 443 ломает старт:

server {
    listen 80;
    listen [::]:80;
    server_name site.example www.site.example;
    root /var/www/site.example;
    location /.well-known/acme-challenge/ { }
}

Сценарий D. Docker/NPM занял 80

docker ps и ss покажут docker-proxy. Либо публикуйте NPM на другом IP, либо не ставьте системный nginx на те же порты. См. Nginx Proxy Manager.

Сценарий E. Два default_server

Оставьте один default_server на listen 80 и один на 443. Остальным vhost — явный server_name site.example.

Как проверить, что проблема устранена

sudo nginx -t
systemctl is-active nginx
sudo ss -tlnp | grep -E ':80|:443'
curl -sI --resolve site.example:80:10.0.20.40 http://site.example/ | head
curl -skI --resolve site.example:443:10.0.20.40 https://site.example/ | head

Ожидание: unit active, порты слушаются процессом nginx, HTTP отдаёт 200/301, не connection refused. PHP при этом может ещё давать 502 — это другая статья.

Если не помогло

  • Тест зелёный, start падает через секунду: AppArmor профиль nginx, смотрите dmesg | grep DENIED, не отключайте AppArmor навсегда.
  • unknown directive — пакет Ubuntu без модуля (echo, headers-more). Ставьте модуль из репозитория или уберите директиву.
  • После обновления пакета сломался сторонний nginx.org vs nginx из Ubuntu — смотрите nginx -v и пути /etc/nginx.
  • Конфиг в /etc/nginx/nginx.conf переопределён include из /etc/nginx/modules-enabled/.

Профилактика

  • Любое изменение — nginx -t затем reload, не restart без нужды.
  • Бэкап /etc/nginx в ту же заявку, что и правка.
  • Не храните единственную копию privkey только в /tmp.
  • Мониторинг: systemctl is-active nginx и код nginx -t в cron с алертом, не молчаливый || true.
  • Один фронт на 80/443: либо nginx, либо Apache, либо NPM.

FAQ

Можно ли killall nginx и запустить бинарник вручную?

Нет как штатный путь. systemd потеряет pid, socket activation и log. Чините unit.

Почему nginx -t OK от sudo, а без sudo ругается на ключ?

Тест без root не читает privkey.pem (права 600). Для диагностики используйте sudo nginx -t.

Нужно ли daemon off в пакете Ubuntu?

Нет. Unit сам управляет демоном. daemon off в основном конфиге ломает ожидания systemd.

Конфликт IPv6 listen [::]:80 и listen 80

На части сборок listen 80 уже dual-stack. Дубль даёт 98. Оставьте один стиль, как в дефолтном пакете.

После certbot nginx не поднимается

Плагин мог вписать пути до успешного выпуска. Проверьте, что fullchain.pem существует, и не используйте --force-renewal как «лечение старта».