Это моя конфигурация nginx, которая автоматически обслуживает публичное S3/MinIO Angular single-page-application по HTTP. Ожидается, что она будет использоваться в конфигурации с внешним прокси, предоставляющим HTTPS. В моём случае это Traefik. См. Простая настройка Traefik docker-compose с Lets Encrypt Cloudflare DNS-01 & TLS-ALPN-01 & HTTP-01 challenges для деталей моей конфигурации.
Этот вариант конфигурации не включает настройку для конфигураций сервиса @angular/localize через S3. См. Как использовать nginx для доставки мультиязычных I18N Angular UI с использованием @angular/localize для примера nginx, обслуживающего статический сайт с несколькими языками и логикой автоматического выбора.
nginx.conf
Здесь вам обычно нужно изменить только следующие переменные:
# Измените это на имя вашего S3-бакета. Убедитесь, что он установлен как публичный!
set $bucket "/my-bucket";
# Измените это на ваш хост MinIO/S3 (без схемы)
set $minio_host "minio.mydomain.com";Полная конфигурация:
# /etc/nginx/nginx.conf
worker_processes auto;
events { worker_connections 1024; }
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
# DNS через Docker-хост (встроенный DNS Docker)
resolver 127.0.0.11 valid=24h ipv6=off;
resolver_timeout 5s;
# Опциональный gzip для текстовых ассетов
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_types
text/plain text/css application/javascript application/json
application/xml application/rss+xml image/svg+xml;
# Дисковый кэш (настройте размер по необходимости)
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=STATIC:100m max_size=10g inactive=30d use_temp_path=off;
server {
listen 80;
server_name _; # Traefik маршрутизирует сюда
# Удобная переменная для пути вашего бакета
# Удобные переменные для пути вашего бакета и хоста MinIO
set $bucket "/my-bucket";
# Измените это на ваш хост MinIO/S3 (без схемы)
set $minio_host "minio.techoverflow.net";
# Перехват upstream 404/403 и маршрутизация в SPA
error_page 404 = @spa;
error_page 403 = @spa;
# Точный корень "/" -> отдача index.html
location = / {
proxy_pass https://$minio_host$bucket/index.html;
proxy_set_header Host $minio_host;
proxy_ssl_server_name on;
proxy_buffering on;
proxy_cache STATIC;
proxy_cache_key $scheme$proxy_host$uri$is_args$args;
# Не кэшировать SPA HTML в браузерах (опционально)
add_header Cache-Control "no-cache, must-revalidate" always;
# Перехват ошибок, чтобы error_page работал даже из слоя кэша
proxy_intercept_errors on;
# Избегать кэширования upstream-ошибок
proxy_no_cache $upstream_status = 404;
proxy_cache_bypass $upstream_status = 404;
proxy_no_cache $upstream_status = 403;
proxy_cache_bypass $upstream_status = 403;
add_header X-Cache-Status $upstream_cache_status always;
}
# Унифицированная обработка всего остального
location / {
proxy_pass https://$minio_host$bucket$uri$is_args$args;
proxy_set_header Host $minio_host;
proxy_ssl_server_name on;
proxy_buffering on;
proxy_http_version 1.1;
proxy_cache STATIC;
proxy_cache_key $scheme$proxy_host$uri$is_args$args;
# Унифицированные TTL для успешных ответов
proxy_cache_valid 200 301 302 24h;
# Не кэшировать upstream-ошибки (предотвращает отдачу обычного NGINX 404)
proxy_no_cache $upstream_status = 404;
proxy_cache_bypass $upstream_status = 404;
proxy_no_cache $upstream_status = 403;
proxy_cache_bypass $upstream_status = 403;
# Опциональное кэширование в браузере (включите, если вы версионруете ассеты)
# add_header Cache-Control "public, max-age=86400, immutable" always;
add_header X-Cache-Status $upstream_cache_status always;
# Гарантия, что SPA fallback срабатывает на 404/403 от origin
proxy_intercept_errors on;
}
# Цель SPA fallback
location @spa {
proxy_pass https://$minio_host$bucket/index.html;
proxy_set_header Host $minio_host;
proxy_ssl_server_name on;
proxy_buffering on;
proxy_cache STATIC;
proxy_cache_key $scheme$proxy_host$uri$is_args$args;
add_header Cache-Control "no-cache, must-revalidate" always;
add_header X-Cache-Status $upstream_cache_status always;
}
}
}docker-compose.yml
Конфигурация docker-compose довольно проста.
services:
nginx:
image: nginx:alpine
restart: unless-stopped
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx_cache:/var/cache/nginx
labels:
- "traefik.enable=true"
- "traefik.http.routers.app-mydomain.rule=Host(`app.mydomain.com`)"
- "traefik.http.routers.app-mydomain.entrypoints=websecure"
- "traefik.http.routers.app-mydomain.tls.certresolver=cloudflare"
- "traefik.http.routers.app-mydomain.tls.domains[0].main=mydomain.com"
- "traefik.http.routers.app-mydomain.tls.domains[0].sans=*.mydomain.com"