Для работы web-сайтов используются различные серверы, обслуживающие HTTP запросы, их называют Web-серверами. Они могут передавать статические страницы и выполнять некоторые скрипты, подключая различные модули, например для работы с PHP, Perl, Asp и другие.
Самые популярные web-серверы в сети интернет - Apache2 и Nginx. Nginx может использоваться в качестве web-сервера или обратного прокси.
В руководстве полагаем, что Linux сервер на базе Debian 9+ или Ubuntu 18+ уже установлен и обновлен.
apt update
apt upgrade
apt update
apt install -y 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 -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 может управляться через 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 расположена по умолчанию в /etc/nginx/
Расположение файлов web-сервера по умолчанию /var/www/
Разместим обычную веб-страницу в /var/www/halfoff.ru/index.html
<html>
<head>
<title>Welcome to halfoff.ru</title>
</head>
<body>
<h1>halfoff.ru welcome page!</h1>
<p>It works!</p>
</body>
</html>
добавим блок конфигурации для нее `/etc/nginx/sites-available/halfoff.ru.conf
server {
server_name halfoff.ru www.halfoff.ru;
listen 80;
if ($host = www.halfoff.ru) {
return 301 http://halfoff.ru$request_uri;
}
root /var/www/halfoff.ru/;
index index.html index.htm index.php;
location / {
try_files $uri $uri/ =404;
}
}
остается "включить" сайт, для чего поместим ссылку в "разрешенных сайтах" на конфигурационный файл, размещенный в "доступных сайтах":
ln -s /etc/nginx/sites-available/halfoff.ru.conf /etc/nginx/sites-enabled/
Выполнить проверку конфигурации nginx -t
и загрузить конфиг nginx -s reload
.
Далее, убедившись, что в DNS есть A-запись, указывающая на ваш сервер, переходим в браузере по этому адресу.
Для подключения выполнения сценариев PHP можно воспользоваться php-fpm
:
apt install -y php php-fpm
и добавить в блок сайта server
в конфигурационном файле /etc/nginx/sites-available/
halfoff.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;
}
Очень часто встречается конфигурация сети, когда серверы расположены в так называемой "демилитаризованной зоне" (DMZ), специальном сегменте сети предприятия, доступ в который строго регламентирован из соображений безопасности.
Предположим, что мы разместили в этой зоне несколько серверов, выдали им серые IP-адреса и предоставили доменное имя локальной сети в домене halfoff.lan
. Для более изящного решения технического задания укажем имена хостов серверов такими, какими они должны быть во внешнем мире в домене halfoff.ru
(локальное имя - IP-адрес - внешнее доменное имя):
/etc/nginx/sites-available/export-dmz.conf
:server {
server_name ~^(?<subdomain>.*)\.halfoff\.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.halfoff.lan:$server_port$request_uri;
}
}
}
Здесь заложена такая логика:
subdomain
, если окончание halfoff.ru
/var/www/dmz/
с именем поддомена - сервера, который необходимо вынести в сеть Интернет (это для безопасности, чтобы можно было включать/отключать серверы)resolver
в качестве локального сервера DNS.Далее, необходимо выполнить следующее, чтобы добавить сервер, например wiki
:
hostname
, совпадающий с поддоменом, выставляемым в интернет, например wiki
с полным именем wiki.halfoff.lan
wiki.halfoff.ru
/var/www/dmz/
с именем поддомена wiki
, можно пустой, или вписать информацию о дате добавления, назначении сервиса и т.п.Включаем
ln -s /etc/nginx/sites-available/export-dmz.conf /etc/nginx/sites-enabled/
nginx -t
nginx -s reload
После всех необходимых настроек виртуальных хостов и обратных прокси довольно важно защитить подключение к серверам от злоумышленников, для чего можно воспользоваться сервисом 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
задание на обновление всех сертификатов на этом сервере.
Конфигурация nginx.conf
по умолчанию выглядит так:
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
будет выглядеть так:
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
.
Для подключения доменных имен субдомена *.k8s.halfoff.ru потребуется сделать несколько вещей в дополнение к приведенному выше конфигурационному файлу:
upstream
для перенаправлени запросов в Ingress K8s по доменному имени *.k8s.halfoff.ruupstream
Ingress K8supstream
по умолчанию для передачи трафика на 443 порт локального интерфейсаНапример:
...
stream {
resolver 10.0.2.2;
upstream k8s_srv_https {
least_conn;
server k8s1.halfoff.lan:443;
server k8s2.halfoff.lan:443;
}
upstream default_https {
server 127.0.0.1:443;
}
map $ssl_preread_server_name $upstream {
~^(.*)k8s\.halfoff\.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 halfoff.ru www.halfoff.ru;
listen 127.0.0.1:443;
...
Теперь все приходящие запросы на внешний интерфейс прокси-сервера (в нашем случае 10.0.2.2) на порт 443 будут обслуживаться stream
веб-сервера nginx
, и в случае совпадения с маской субдомена *.k8s.halfoff.ru прозрачно перенаправится в Ingress кластера K8s, в противном случае направится на локальный интерфейс 127.0.0.1:443 и дальше обработается правилами virtual hosts
.