Конфигурация nginx Docker для обслуживания публичного S3/MinIO Angular single-page-application по HTTP

Это моя конфигурация 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

Здесь вам обычно нужно изменить только следующие переменные:

nginx_minio_spa.conf
    # Измените это на имя вашего S3-бакета. Убедитесь, что он установлен как публичный!
    set $bucket "/my-bucket";
    # Измените это на ваш хост MinIO/S3 (без схемы)
    set $minio_host "minio.mydomain.com";

Полная конфигурация:

nginx.conf
# /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 довольно проста.

docker-compose.yml
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"

Check out similar posts by category: Nginx S3 Angular