Nginx Docker
Nginx Docker
Обзор и цели
В этой лабораторной работе вы построите полноценную микросервисную инфраструктуру с
NGINX в роли центрального маршрутизатора. Все компоненты запускаются локально через
Docker Compose — установка дополнительного ПО не требуется.
⚙ Требования к окружению
• Docker Desktop (Windows/macOS) или Docker Engine + Docker Compose plugin (Linux)
• Версия Docker: 20.10+, Docker Compose: 2.0+
• Свободная оперативная память: ~1 GB
• Свободные порты: 80, 443, 8080, 8081, 9090 (можно изменить в .env файле)
• curl установлен в системе (для тестирования из хоста)
• Проверка: docker --version && docker compose version
Структура проекта
Создайте следующую структуру директорий. Все файлы описаны в соответствующих
заданиях.
Страница 1 из 21
NGINX + Docker Compose DevOps / Инфраструктура
nginx-lab/
├── [Link] # Главный оркестратор
├── .env # Переменные окружения
├── nginx/
│ ├── [Link] # Основная конфигурация
│ ├── conf.d/
│ │ ├── [Link] # Задания 1-2
│ │ ├── [Link] # Задания 3-4
│ │ ├── [Link] # Задание 5
│ │ ├── [Link] # Задание 6
│ │ └── [Link] # Задание 8
│ ├── ssl/ # TLS сертификаты
│ │ ├── [Link]
│ │ └── [Link]
│ └── html/ # Статический контент
│ ├── [Link]
│ ├── [Link]
│ └── [Link]
├── services/
│ ├── api-v1/ # Flask backend v1
│ │ ├── [Link]
│ │ └── Dockerfile
│ ├── api-v2/ # Flask backend v2
│ │ ├── [Link]
│ │ └── Dockerfile
│ ├── api-slow/ # Медленный сервис (для LB тестов)
│ │ ├── [Link]
│ │ └── Dockerfile
│ └── ws-server/ # WebSocket сервер
│ ├── [Link]
│ └── Dockerfile
└── tests/
└── test_all.sh # Скрипт авто-проверки
# [Link]
version: "3.9"
services:
nginx:
image: nginx:1.25-alpine
container_name: nginx_gateway
ports:
- "${HTTP_PORT:-80}:80"
- "${HTTPS_PORT:-443}:443"
volumes:
- ./nginx/[Link]:/etc/nginx/[Link]:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
- ./nginx/html:/usr/share/nginx/html:ro
- nginx_logs:/var/log/nginx
depends_on:
- api_v1
- api_v2
Страница 2 из 21
NGINX + Docker Compose DevOps / Инфраструктура
- ws_server
networks:
- frontend
- backend
restart: unless-stopped
api_v1:
build: ./services/api-v1
container_name: api_v1
environment:
- SERVICE_VERSION=v1
- SERVICE_COLOR=blue
networks:
- backend
restart: unless-stopped
api_v2:
build: ./services/api-v2
container_name: api_v2
environment:
- SERVICE_VERSION=v2
- SERVICE_COLOR=green
networks:
- backend
restart: unless-stopped
api_slow:
build: ./services/api-slow
container_name: api_slow
networks:
- backend
restart: unless-stopped
ws_server:
build: ./services/ws-server
container_name: ws_server
networks:
- backend
restart: unless-stopped
volumes:
nginx_logs:
networks:
frontend:
backend:
app = Flask(__name__)
VERSION = [Link]('SERVICE_VERSION', 'unknown')
COLOR = [Link]('SERVICE_COLOR', 'grey')
HOST = [Link]()
Страница 3 из 21
NGINX + Docker Compose DevOps / Инфраструктура
@[Link]('/api/info')
def info():
return jsonify({
'version': VERSION,
'color': COLOR,
'host': HOST,
'time': [Link]()
})
@[Link]('/api/health')
def health():
return jsonify({'status': 'ok', 'version': VERSION})
@[Link]('/api/echo', methods=['GET','POST'])
def echo():
return jsonify({
'method': [Link],
'headers': dict([Link]),
'body': request.get_json(silent=True)
})
if __name__ == '__main__':
[Link](host='[Link]', port=5000)
services/ws-server/[Link]
// WebSocket эхо-сервер
const WebSocket = require('ws');
const wss = new [Link]({ port: 8765 });
Страница 4 из 21
NGINX + Docker Compose DevOps / Инфраструктура
# nginx/[Link]
user nginx;
worker_processes auto;
error_log /var/log/nginx/[Link] warn;
pid /var/run/[Link];
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/[Link];
default_type application/octet-stream;
# Логирование
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" rt=$request_time';
# Производительность
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# Gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 256;
gzip_types text/plain text/css application/json
application/javascript text/xml;
Страница 5 из 21
NGINX + Docker Compose DevOps / Инфраструктура
include /etc/nginx/conf.d/*.conf;
}
# nginx/conf.d/[Link]
server {
listen 80 default_server;
server_name _;
root /usr/share/nginx/html;
index [Link];
# Основной маршрут
location / {
try_files $uri $uri/ =404;
}
Страница 6 из 21
NGINX + Docker Compose DevOps / Инфраструктура
Страница 7 из 21
NGINX + Docker Compose DevOps / Инфраструктура
# nginx/conf.d/[Link]
server {
listen 80;
server_name [Link]; # Отдельный виртуальный хост
# Стандартные proxy-заголовки
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 X-API-Version $api_version;
# Таймауты
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
proxy_read_timeout 30s;
# Буферы
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
Страница 8 из 21
NGINX + Docker Compose DevOps / Инфраструктура
Страница 9 из 21
NGINX + Docker Compose DevOps / Инфраструктура
# Weighted round-robin
location /api/lb {
proxy_pass [Link]
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
# IP-hash (sticky)
location /api/sticky {
proxy_pass [Link]
proxy_http_version 1.1;
proxy_set_header Connection "";
add_header X-Upstream-Addr $upstream_addr always;
}
Страница 10 из 21
NGINX + Docker Compose DevOps / Инфраструктура
mkdir -p nginx/ssl
# Проверка сертификата:
openssl x509 -in nginx/ssl/[Link] -noout -text | grep -E 'Subject|Validity|Not'
# Сертификаты
ssl_certificate /etc/nginx/ssl/[Link];
ssl_certificate_key /etc/nginx/ssl/[Link];
root /usr/share/nginx/html;
index [Link];
location / {
Страница 11 из 21
NGINX + Docker Compose DevOps / Инфраструктура
Задание 5: HTTPS
33. Обновите порты в [Link] (если ещё не указаны): добавьте
443:443
34. Примените: docker compose restart nginx
35. Проверьте HTTPS: curl -k [Link] — флаг -k игнорирует ошибку
самоподписанного сертификата
36. Проверьте редирект: curl -v [Link] — должен быть 301 →
[Link]
37. Проверьте HTTP/2: curl -k --http2 -I [Link] — в заголовках
найдите :version: h2 или HTTP/2
38. Посмотрите информацию о TLS: curl -kv [Link] 2>&1 | grep -E 'TLS|
SSL|cipher'
39. Откройте [Link] в браузере — изучите информацию о сертификате
через значок замка
40. Раскомментируйте HSTS заголовок, проверьте его наличие в ответах.
Объясните риски включения HSTS с самоподписанным сертификатом
6.1 [Link]
# nginx/conf.d/[Link]
Страница 12 из 21
NGINX + Docker Compose DevOps / Инфраструктура
server {
listen 80;
server_name [Link];
proxy_pass [Link]
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
Страница 13 из 21
NGINX + Docker Compose DevOps / Инфраструктура
Задание 6: Безопасность
41. Добавьте [Link] [Link] в /etc/hosts
42. Создайте .htpasswd и пересоберите: docker compose restart nginx
43. Проверьте заголовки безопасности: curl -I [Link] —
должны быть X-Frame-Options, X-Content-Type-Options и другие
44. Проверьте rate limit: for i in {1..15}; do curl -s -o /dev/null -w "%{http_code}\n"
[Link] done — при превышении должен появиться
429
45. Проверьте auth limit: запустите curl 8 раз к /auth — первые 3 проходят
мгновенно, остальные тормозят или возвращают 429
46. Проверьте ACL: curl [Link] с хоста — если получаете
403, попробуйте из контейнера: docker exec nginx_gateway wget -qO-
[Link]
47. Проверьте Basic Auth: curl [Link] — 401; curl -u
student:password123 [Link] — 200
48. Зафиксируйте все заголовки безопасности из ответа NGINX и объясните
назначение каждого
Страница 14 из 21
NGINX + Docker Compose DevOps / Инфраструктура
proxy_cache api_cache;
proxy_cache_valid 200 30s; # кэш 30 сек
proxy_cache_valid 404 5s;
proxy_cache_methods GET;
proxy_cache_use_stale error timeout updating;
proxy_cache_lock on;
- nginx_cache:/var/cache/nginx
8.1 [Link]
Страница 15 из 21
NGINX + Docker Compose DevOps / Инфраструктура
# nginx/conf.d/[Link]
server {
listen 80;
server_name [Link];
location / {
root /usr/share/nginx/html;
index [Link];
}
# WebSocket proxy
location /ws {
proxy_pass [Link]
proxy_http_version 1.1;
# Долгое соединение
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
# tests/test_ws.py
import asyncio, json, websockets
# Отправить сообщение
await [Link]('Hello, NGINX!')
# Получить echo
echo = await [Link]()
data = [Link](echo)
print(f"Echo received: {data['original']} at {data['timestamp']}")
assert data['type'] == 'echo'
print('✅ WebSocket proxy works correctly!')
[Link](test_websocket())
Страница 16 из 21
NGINX + Docker Compose DevOps / Инфраструктура
# Войти в контейнер:
docker exec -it nginx_gateway sh
Страница 17 из 21
NGINX + Docker Compose DevOps / Инфраструктура
d = [Link](line)
print(f\"{d['status']} {d['duration']}s {d['uri']}\")
"
Задание 9: Логирование
64. Обновите формат логов и перезапустите NGINX
65. Сделайте 20+ разных запросов (разные endpoint'ы, методы, параметры)
66. Выполните анализ: найдите самый медленный запрос
67. Найдите запросы с кэш HIT и MISS
68. Подсчитайте процент 2xx/4xx/5xx ответов в логах
69. Экспортируйте лог: docker cp nginx_gateway:/var/log/nginx/[Link]
./[Link] и изучите файл
70. Напишите однострочник (python/awk/jq), который выводит среднее время
ответа за последние 50 запросов
# Добавить в [Link]:
nginx_exporter:
image: nginx/nginx-prometheus-exporter:latest
command:
Страница 18 из 21
NGINX + Docker Compose DevOps / Инфраструктура
- -[Link]-uri=[Link]
ports:
- "9113:9113"
networks:
- backend
depends_on:
- nginx
prometheus:
image: prom/prometheus
volumes:
- ./[Link]:/etc/prometheus/[Link]
ports:
- "9090:9090"
networks:
- backend
# [Link]
global:
scrape_interval: 5s
scrape_configs:
- job_name: nginx
static_configs:
- targets: ['nginx_exporter:9113']
Откройте [Link] → Graph → введите запрос: nginx_http_requests_total и
понаблюдайте метрики в реальном времени.
Б3 Автоматическая проверка
Создайте tests/test_all.sh — скрипт, который автоматически проверяет все задания:
#!/bin/bash
PASS=0; FAIL=0
check() { local desc=$1; local cmd=$2; local expected=$3
result=$(eval $cmd 2>/dev/null)
if echo "$result" | grep -q "$expected"; then
echo "✅ $desc"; PASS=$((PASS+1))
else
echo "❌ $desc (got: $result)"; FAIL=$((FAIL+1))
fi
}
Страница 19 из 21
NGINX + Docker Compose DevOps / Инфраструктура
Обязательные пункты
☐ docker compose up --build проходит без ошибок
☐ docker compose ps — все 5 контейнеров в статусе running
☐ curl [Link] возвращает 200 с HTML-страницей
☐ server_tokens off — в заголовке Server нет версии NGINX
☐ Gzip работает — curl -H 'Accept-Encoding: gzip' -I [Link] показывает Content-
Encoding: gzip
☐ /api/v1 и /api/v2 корректно проксируются к разным backend-сервисам
☐ Балансировка работает — 10 запросов к /api/lb возвращают ответы от разных инстансов
☐ Остановка одного backend не ломает балансировщик
☐ HTTPS доступен на 443, самоподписанный сертификат установлен
☐ HTTP перенаправляет на HTTPS (301)
☐ Rate limit срабатывает — 20+ запросов возвращают 429
☐ Заголовки безопасности присутствуют в ответах
☐ Basic Auth работает — без пароля 401, с паролем 200
☐ proxy_cache работает — второй запрос к /api/cached даёт X-Cache-Status: HIT
☐ WebSocket соединение проходит через NGINX proxy
☐ JSON логи содержат поля: time, ip, method, uri, status, duration
☐ nginx -t проходит без ошибок
Дополнительные (бонус)
☐ Нагрузочный тест проведён и результаты задокументированы
☐ Prometheus Exporter запущен, метрики собираются
☐ Автоматический тест test_all.sh проходит все проверки
Требования к отчёту
Отчёт должен содержать следующие разделы:
Страница 20 из 21
NGINX + Docker Compose DevOps / Инфраструктура
📦 Сдача работы
Сдайте архив с именем nginx-lab-<фамилия>.[Link], содержащий:
• Все конфигурационные файлы проекта (без node_modules, __pycache__)
• Файл отчёта [Link] или [Link]
• Файл [Link] (экспортированный из контейнера)
Команда для создания архива: tar --exclude='*.pyc' --exclude='node_modules' -czf nginx-
[Link] nginx-lab/
Проблема Решение
nginx -t: unknown Модуль не включён. Проверьте nginx -V 2>&1 | grep
directive modules и наличие нужного модуля
502 Bad Gateway Backend контейнер не запущен. docker compose ps, docker
logs api_v1
listen conflict: already Два server-блока слушают один порт/server_name.
taken Сделайте nginx -T и найдите дубликат
connect() failed (111) NGINX не запущен или PID-файл устарел. docker compose
/var/run/[Link] restart nginx
port is already allocated Порт 80/443 занят другим процессом. lsof -i :80 или
измените порты в .env
permission denied Файл не смонтирован или нет прав. Проверьте docker-
/etc/nginx/ssl/.htpasswd compose volumes и chmod 644
WebSocket: 101 не Нет заголовков Upgrade/Connection. Убедитесь в наличии
возвращается map-блока и proxy_set_header Upgrade
Кэш не работает (всегда proxy_cache_path не указан в http-блоке, или том не
MISS) смонтирован. docker exec nginx cat /etc/nginx/[Link] |
grep cache
Страница 21 из 21