Sysadmin
May 15

Установка Nginx на Debian/Ubuntu Linux

Установка Nginx на Linux

Что такое Nginx

Для работы web-сайтов используются различные серверы, обслуживающие HTTP запросы, их называют Web-серверами. Они могут передавать статические страницы и выполнять некоторые скрипты, подключая различные модули, например для работы с PHP, Perl, Asp и другие.
Самые популярные web-серверы в сети интернет - Apache2 и Nginx. Nginx может использоваться в качестве web-сервера или обратного прокси.

Предварительные требования

В руководстве полагаем, что Linux сервер на базе Debian 9+ или Ubuntu 18+ уже установлен и обновлен.

apt update
apt upgrade

Установка Nginx

Установка из стандартного репозитория

apt update
apt install -y nginx

Установка из репозитория Nginx

Определить подходящую ветку:

  • mainline - содержит самые новые функции, но не исключает ошибки
  • stable - включает только критические правки ошибок

Добавить подпись для репозитория nginx

wget -qO - https://nginx.org/keys/nginx_signing.key | apt-key add -

Добавить в apt репозиторий, указав дистрибутив и релиз:

DISTRIB=`cat /etc/os-release | grep "^ID=" | awk -F'=' '{print $2}'`
RELEASE=`cat /etc/os-release | grep "^VERSION_CODENAME=" | awk -F'=' '{print $2}'`

cat <<EOF >>/etc/apt/sources.list.d/nginx.list
deb https://nginx.org/packages/$DISTRIB/ $RELEASE nginx
deb-src https://nginx.org/packages/$DISTRIB/ $RELEASE nginx
EOF

Или версию mainline

deb https://nginx.org/packages/mainline/$DISTRIB/ $RELEASE nginx
deb-src https://nginx.org/packages/mainline/$DISTRIB/ $RELEASE nginx

Обновить списки пакетов и установить nginx

apt update
apt install -y nginx

Проверка работоспособности Nginx

Проверить версию Nginx

nginx -v
# nginx version: nginx/1.21.2

Проверить прослушивание порта 80

curl -v 127.0.0.1
# HTTP/1.1 200 OK
# Server: nginx/1.21.2

Управление Nginx

Nginx может управляться через systemctl

systemctl start nginx
systemctl enable nginx
systemctl reload nginx
systemctl status nginx
systemctl stop nginx
systemctl disable nginx

Во время работы перед применением новой конфигурации nginx нужно выполнить проверку этой конфигурации

nginx -t

При успешном выполнении выполнить применение конфигурации

nginx -s reload

Настройка виртуальных хостов Nginx

Конфигурация nginx расположена по умолчанию в /etc/nginx/
Расположение файлов web-сервера по умолчанию /var/www/
Разместим обычную веб-страницу в /var/www/antroot.ru/index.html

<html>
  <head>
    <title>Welcome to antroot.ru</title>
  </head>
  <body>
    <h1>antroot.ru welcome page!</h1>
    <p>It works!</p>
  </body>
</html>

добавим блок конфигурации для неё /etc/nginx/sites-available/antroot.ru.conf

server {
    server_name antroot.ru www.antroot.ru;
    listen 80;
    if ($host = www.antroot.ru) {
        return 301 http://antroot.ru$request_uri;
    }
    root /var/www/antroot.ru/;
    index index.html index.htm index.php;
    location / {
            try_files $uri $uri/ =404;
    }
}

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

ln -s /etc/nginx/sites-available/antroot.ru.conf /etc/nginx/sites-enabled/

Выполнить проверку конфигурации nginx -t и загрузить конфиг nginx -s reload.
Далее, убедившись, что в DNS есть A-запись, указывающая на ваш сервер, переходим в браузере по этому адресу.

Подключение PHP

Для подключения выполнения сценариев PHP можно воспользоваться php-fpm:

apt install -y php php-fpm

и добавить в блок сайта server в конфигурационном файле /etc/nginx/sites-available/antroot.ru.conf обработку файлов с расширением php

location ~ \.php$ {
    try_files $uri = 404;
    include fastcgi_params;
    fastcgi_pass  unix:/var/run/php7.3-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
}

Настройка Reverse Proxy на Nginx

Очень часто встречается конфигурация сети, когда серверы расположены в так называемой "демилитаризованной зоне" (DMZ), специальном сегменте сети предприятия, доступ в который строго регламентирован из соображений безопасности.
Предположим, что мы разместили в этой зоне несколько серверов, выдали им серые IP-адреса и предоставили доменное имя локальной сети в домене antroot.lan. Для более изящного решения технического задания укажем имена хостов серверов такими, какими они должны быть во внешнем мире в домене antroot.ru (локальное имя - IP-адрес - внешнее доменное имя):

  • www.antroot.lan - 10.0.3.50 - www.antroot.ru
  • mail.antroot.lan - 10.0.3.51 - mail.antroot.ru
  • wiki.antroot.lan - 10.0.3.52 - wiki.antroot.ru
    Для доступа к ним из внешнего мира настроим reverse proxy на nginx в конфигурации /etc/nginx/sites-available/export-dmz.conf:
server {
  server_name ~^(?<subdomain>.*)\.antroot\.ru$;
  listen 80;
  resolver 10.0.2.2;
  location / {
      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 Connection "";
      if ( -f /var/www/dmz/$subdomain) {
          proxy_pass http://$subdomain.antroot.lan:$server_port$request_uri;
      }
  }
}

Здесь заложена такая логика:

  1. В строке 2 из доменного имени извлекается первая часть subdomain, если окончание antroot.ru
  2. В строке 10 проверяется файл в директории /var/www/dmz/ с именем поддомена - сервера, который необходимо вынести в сеть Интернет (это для безопасности, чтобы можно было включать/отключать серверы)
  3. В строке 11, при наличии файла поддомена из предыдущего пункта, выполняется прокси-запрос на сервер в DMZ
  4. Чтобы выполнилось разрешение имени сервера в локальном сети, указывается resolver в качестве локального сервера DNS.

Далее, необходимо выполнить следующее, чтобы добавить сервер, например wiki:

  • установить сервер в DMZ, задать ему hostname, совпадающий с поддоменом, выставляемым в интернет, например wiki с полным именем wiki.antroot.lan
  • добавить во "внешний" DNS A-запись с поддоменом сервера, указывающую на обратный прокси, например wiki.antroot.ru
  • создать файл в /var/www/dmz/ с именем поддомена wiki, можно пустой, или вписать информацию о дате добавления, назначении сервиса и т.п.

Включаем:

ln -s /etc/nginx/sites-available/export-dmz.conf /etc/nginx/sites-enabled/
nginx -t
nginx -s reload

Защита сервера с помощью TLS

После всех необходимых настроек виртуальных хостов и обратных прокси довольно важно защитить подключение к серверам от злоумышленников, для чего можно воспользоваться сервисом Let's Encrypt, получить сертификат SSL и установить на web-сервер.
В качестве инструмента для работы с Let's Encrypt используется certbot, входящий в состав стандартного репозитория Debian/Ubuntu Linux

apt install -y certbot python3-certbot-nginx

После установки запустить certbot, ввести адрес для уведомлений, выбрать из найденых в конфигурационных файлах nginx доменов и получить сертификат. После успешного получения, certbot запишет сертификат в ssl_certificate блока в конфигурации nginx, и предложит сделать редирект с небезопасного на защищенный адрес.
А также установит в crontab задание на обновление всех сертификатов на этом сервере.

Подключение кластера K8s через upstream

Конфигурация nginx.conf по умолчанию выглядит так:

nginx.conf - default

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
    keepalive_timeout  65;
    #gzip  on;
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Подключим upstream в kube_apiserver в nginx.conf:

stream {
    upstream kube_apiserver {
        least_conn;
        # адреса узлов кластера
        server 10.0.2.2:6443;
        server 10.0.2.3:6443;
    }
    server {
        listen        1.2.3.4:6443; # внешний IP-адрес
        proxy_pass    kube_apiserver;
        proxy_timeout 10m;
        proxy_connect_timeout 1s;
    }
}

и слегка подкрутим параметры подключений.
Полный конфигурационный файл nginx.conf будет выглядеть так:

nginx.conf + kubeapi

error_log  stderr notice;
pid        /var/run/nginx.pid;

user  nginx;
#worker_processes  auto;
worker_processes 2;
worker_rlimit_nofile 130048;
worker_shutdown_timeout 10s;

events {
    multi_accept on;
    use epoll;
    worker_connections 16384;
}

stream {
    upstream kube_apiserver {
        least_conn;
        server 10.0.2.2:6443;
        server 10.0.2.3:6443;
    }

    server {
        listen        1.2.3.4:16443; # внешний IP-адрес и порт
        proxy_pass    kube_apiserver;
        proxy_timeout 10m;
        proxy_connect_timeout 1s;
    }
}
http {
    aio threads;
    aio_write on;
    tcp_nopush on;
    tcp_nodelay on;

    keepalive_timeout 5m;
    keepalive_requests 100;
    reset_timedout_connection on;
    server_tokens off;
    autoindex off;

    server {
        listen 8081;
        location /healthz {
            access_log off;
            return 200;
        }
        location /stub_status {
            stub_status on;
            access_log off;
        }
    }

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

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;
    #keepalive_timeout  65;
    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

При этом не теряется возможность подключать сайты из sites_enabled.

Подключение доменных имен поддомена в Ingress K8s

Для подключения доменных имен субдомена *.k8s.antroot.ru потребуется сделать несколько вещей в дополнение к приведенному выше конфигурационному файлу:

  1. Настроить upstream для перенаправление запросов в Ingress K8s по доменному имени *.k8s.antroot.ru
  2. Подключить перенаправление запросов с 443 порта внешнего интерфейса сервера в upstream Ingress K8s
  3. Настроить upstream по умолчанию для передачи трафика на 443 порт локального интерфейса
  4. Настроить всем виртуальным хостам подключение на 443 порт локального интерфейса 127.0.0.1

Например:

...
stream {
    resolver 10.0.2.2;
    upstream k8s_srv_https {
        least_conn;
        server k8s1.antroot.lan:443;
        server k8s2.antroot.lan:443;
    }
    upstream default_https {
        server 127.0.0.1:443;
    }

    map $ssl_preread_server_name $upstream {
        ~^(.*)k8s\.antroot\.ru  k8s_srv_https;
        default         default_https;
    }
    server {
        listen 10.0.2.2:443;
        proxy_pass $upstream;
        ssl_preread on;
        tcp_nodelay on;
        proxy_timeout 10m;
        proxy_connect_timeout 2s;
    }

    log_format basic '$remote_addr [$time_local] '
            '$protocol $status $bytes_sent $bytes_received '
            '$session_time "$upstream_addr" '
            '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';

    access_log /var/log/nginx/upstream_access.log basic;
    error_log  /var/log/nginx/upstream_error.log;
}
...

и во всех конфигурационных файлах виртуальных сайтов привязать прослушивание к localhost:

server {
    server_name antroot.ru www.antroot.ru;
    listen 127.0.0.1:443;
...

Теперь все приходящие запросы на внешний интерфейс прокси-сервера (в нашем случае 10.0.2.2) на порт 443 будут обслуживаться stream веб-сервера nginx, и в случае совпадения с маской субдомена *.k8s.antroot.ru прозрачно перенаправится в Ingress кластера K8s, в противном случае направится на локальный интерфейс 127.0.0.1:443 и дальше обработается правилами virtual hosts.