アップストリームへの接続中に Nginx connect() が失敗しました (111: 接続が拒否されました)。クライアント: 192.168.128.1、サーバー: hello-1.local

アップストリームへの接続中に Nginx connect() が失敗しました (111: 接続が拒否されました)。クライアント: 192.168.128.1、サーバー: hello-1.local

Django + docker + nginx 環境で SSL を設定しようとしています。しかし、次のエラーが発生しました:

*19 アップストリームへの接続中に connect() が失敗しました (111: 接続が拒否されました)。クライアント: 192.168.128.1、サーバー: hello-1.local、リクエスト: "GET / HTTP/1.1"、アップストリーム: "https://192.168.128.4:443/"、ホスト: "hello-1.local"

私のNginx設定:

client_max_body_size 10M;

upstream web {  
  ip_hash;
  server web:443;
}

server {
    listen 80;
    server_name hello-1.local;
    return 301 https://$host$request_uri;
}

server {    
    
    location /static/ {    
        autoindex on;    
        alias /src/static/; 
    }

    location /media/ {
        autoindex on;
        alias /src/media/;
    }

``

    location / {
        proxy_pass https://web/;
    }
    
    listen 443 ssl;
    server_name hello-1.local;
    ssl_certificate /etc/certs/hello-1.local.crt;
    ssl_certificate_key /etc/certs/hello-1.local.key;
    
} 

docker-compose.yml:

version: "3"

volumes:
  local_postgres_data: {}
  local_postgres_data_backups: {}

services:
  nginx:
    image: nginx:alpine
    container_name: nz01
    ports:
      - 443:443
      - 80:80
    volumes:
      - ./src:/src
      - ./config/nginx:/etc/nginx/conf.d
      - ./config/certs:/etc/certs
    depends_on:
      - web
    networks:
      - djangonetwork
  web:
    build:
      context: .
      dockerfile: compose/django/Dockerfile
    container_name: dz01
    depends_on:
      - db
    volumes:
      - ./src:/src
    expose:
      - 8000
    links:
      - redis
    env_file:
      - ./.envs/.django
    networks:
      - djangonetwork
  db:
    build:
      context: .
      dockerfile: compose/postgres/Dockerfile
    container_name: pz01
    env_file:
      - ./.envs/.postgres
    volumes:
      - local_postgres_data:/var/lib/postgresql/data
      - local_postgres_data_backups:/backups
    networks:
      - djangonetwork
  redis:
    image: redis:alpine
    container_name: rz01
    ports:
      - "6379:6379"
    networks:
      - djangonetwork

networks:
  djangonetwork:
    driver: bridge

ブラウザで 502 Bad Gateway エラーが発生し、SSL がなくても Web サイトは正常に動作します。何が問題なのでしょうか?

答え1

では、上流とは何でしょうか?

アップストリームはここで定義されます:

upstream web {  
  ip_hash;
  server web:443;
}

これを最初に読んだところ、Nginx は という名前のアップストリーム サーバーに正しく接続できないようですweb

これには複数の理由が考えられます:

  • Nginxが解決できないweb
  • 実行中のウェブサーバーはwebhttps/ポート443を提供していません
  • 実行中のウェブサーバーはwebホスト名に対して有効で信頼できる証明書を使用していませんweb

docker-compose.yml を見てみましょう:

  • アプリケーションはwebポート 8000 に公開されていますが、Nginx ではポート 443 に接続したいのですが、これも間違ったプロトコルを使用しています (おそらく)

したがって、解決策としては、nginx.conf のupstream-config を次のように変更します。

upstream web {  
  ip_hash;
  server web:8000;
}

ロケーションブロックは次のようになります (https --> http):

location / {
    proxy_pass http://web/;
}

プロキシ/アップストリームでの SSL/TLS について: これについては Nginx のドキュメントを参照してください。http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ssl_verify

答え2

私の Web アプリケーションでも同様のセットアップを行っており、Nginx は Dockerized Django および React のリバース プロキシとして機能しています。また、ローカル開発では SSL に自己署名証明書を使用しています。

React (Next.js) が Django の REST API からデータを取得しているのですが、一部のリクエストはサーバーから、その他のリクエストはクライアントから来ているため、苦労していました。サーバーベースのリクエストはhttp://backend:8000(Docker サービス名と公開ポート) を使用できましたが、クライアントベースのリクエストは を経由する必要がありましたhttps://example.local

もし誰かがこれに困っていて、Swagger UI (つまり、drf-yasg) を使用している場合、これが私のアキレス腱でした--- OpenAPI の「DEFAULT_API_URL」を設定する必要があります。 で自己署名 SSL 証明書をお持ちの場合は、 をSwagger URL としてexample.local設定する必要があります。 の場合、私の は次のとおりです。https://example.localdrf-yasgsettings.py

# Swagger
ENDPOINT_DOMAIN = "https://example.com"
if DEBUG:
    ENDPOINT_DOMAIN = "https://example.local"
SWAGGER_SETTINGS = {
    'SECURITY_DEFINITIONS': {
        'basic': {
            'type': 'basic'
        }
    },
    'DEFAULT_API_URL': ENDPOINT_DOMAIN,
}

さらに、Next.js 構成 ( next.config.js) でこれを一致させる必要がありました。

const nextConfig = {
  ...
  assetPrefix: 'https://example.local',
  ...
}

最終的に、私の Nginx 設定は次のようになります。

server {
  listen 80;
  listen [::]:80;

  server_name example.local;
  return 302 https://example.local$request_uri;
}

# Main server directive
server {
  http2               on;

  listen 443          default ssl;
  listen [::]:443     default ssl;

  ssl_certificate     /etc/nginx/certs/example.test.crt;
  ssl_certificate_key /etc/nginx/certs/example.test.key;

  root                /app;
  server_name         example.local;

  charset utf-8;

  gzip on;
  gzip_disable "msie6";
  gzip_comp_level 6;
  gzip_min_length 1100;
  gzip_buffers 16 8k;
  gzip_proxied any;
  gzip_types
    text/plain
    text/css
    text/js
    text/xml
    text/javascript
    application/javascript
    application/json
    application/xml
    application/rss+xml
    image/svg+xml;

  # Setup frontend requests to use port 3000
  location @frontend {
    internal;
    root       /app/frontend/;
    proxy_pass http://frontend:3000;

    proxy_redirect off;
    proxy_set_header Host              $host;
    proxy_set_header X-Forwarded-For   $remote_addr;
    proxy_set_header X-Forwarded-Host  $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-NginX-Proxy     true;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Url-Scheme      $scheme;
  }

  # Setup backend requests to use port 8000
  location @backend {
    proxy_pass http://backend:8000;

    proxy_redirect off;
    proxy_ssl_verify off;
    proxy_set_header Host              $host;
    proxy_set_header X-Forwarded-For   $remote_addr;
    proxy_set_header X-Forwarded-Host  $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-NginX-Proxy     true;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Url-Scheme      $scheme;
  }

  # Frontend =============================================
  location / {
    try_files $uri @frontend;
  }

  location ~ ^/assets/(.*)$ {
    root      /app/frontend/public/;
    try_files $uri @frontend;
  }

  location ~ ^/favicon(.*)$ {
    root      /app/frontend/public/assets/favicon/;
    try_files $uri @frontend;
  }

  location ~ ^/_next/(.*)$ {
    root      /app/frontend/;
    try_files $uri @frontend;
  }

  location /_next/webpack-hmr {
    root      /app/frontend/;
    try_files $uri @frontend;

    # Websockets
    proxy_http_version 1.1;
    proxy_set_header   Connection "upgrade";
    proxy_set_header   Upgrade $http_upgrade;
  }

  location /404 {
    try_files $uri @frontend;
  }


  # Backend ===============================================
  location ~ ^/swagger(.*)$ {
    try_files $uri @backend;
  }

  location ~ ^/redoc(.*)$ {
    try_files $uri @backend;
  }

  location ~ ^/admin(.*)$ {
    try_files $uri @backend;
  }

  location ~ ^/api(.*)$ {
    try_files $uri @backend;
  }

  location ~ ^/webmention(.*)$ {
    try_files $uri @backend;
  }

  location ~ ^/rss(.*)$ {
    try_files $uri @backend;
  }

  location /sitemap.xml {
    try_files $uri @backend;
  }

  location ~ ^/static/(.*)$ {
    root      /app/backend/;
    try_files $uri @backend;

    autoindex on;
  }

  location ~ ^/uploads/(.*)$ {
    root      /app/backend/;
    try_files $uri @backend;
  }

  location /(500|502|503|504) {
    try_files $uri @backend;
  }

  # Error handling
  error_page 404 /404;
  error_page 500 502 503 504 /500;
}

関連情報