You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nginx反向代理与端口转发失效:无法公网访问Airflow服务

问题描述

我在访问本地托管的网站时遇到问题,希望让部署在Docker容器中、Nginx代理后的Apache Airflow服务通过公网访问,现有配置如下:

  • 拥有NoIP主机名stuff.ddns.net,已配置IP自动更新,确保始终指向路由器;
  • 路由器已将80、443端口转发至本地Linux机器的静态IP;
  • Linux机器的Docker容器中部署了Airflow Web服务器,设置环境变量AIRFLOW__WEBSERVER__BASE_URL: 'https://stuff.ddns.net/airflow'。

尝试访问stuff.ddns.net/airflow时,浏览器报错:

Safari can't open the page "stuff.ddns.net/airflow" because Safari can't connect to the server "stuff.ddns.net"

我的nginx.conf配置:

# top-level http config for websocket headers
# If Upgrade is defined, Connection = upgrade
# If Upgrade is empty, Connection = close
events { 
    worker_connections 1024;
}

http {
    map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
    }

    upstream airflow {
        server localhost:8080;
    }

    server {
        listen [::]:80;
        server_name stuff.ddns.net;
        return 302 https://$host$request_uri;
    }

    server {
        listen [::]:443 ssl;

        server_name stuff.ddns.net;

        ssl_certificate /run/secrets/stuff_ddns_net_pem_chain;
        ssl_certificate_key /run/secrets/stuff_ddns_net_key;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_dhparam /run/secrets/dhparam.pem;
        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';

        location /airflow/ {
            proxy_pass http://airflow;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    }
}

补充docker-compose.yml(截取关键部分):

version: '3.7'

x-airflow-common:
  &airflow-common
  image: ${AIRFLOW_IMAGE_NAME:-apache/airflow:2.4.0}
  # build: .
  environment:
    &airflow-common-env
    AIRFLOW__CORE__EXECUTOR: CeleryExecutor
    AIRFLOW__CORE__SQL_ALCHEMY_CONN_CMD: 'cat /run/secrets/sql_alchemy_conn'
    AIRFLOW__CELERY__RESULT_BACKEND_CMD: 'cat /run/secrets/result_backend'
    AIRFLOW__CELERY__BROKER_URL: redis://:@redis:6379/0
    AIRFLOW__CORE__FERNET_KEY: ''
    AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION: 'true'
    AIRFLOW__CORE__LOAD_EXAMPLES: 'false'
    AIRFLOW__API__AUTH_BACKENDS: 'airflow.api.auth.backend.basic_auth'
    AIRFLOW__WEBSERVER__BASE_URL: 'https://stuff.ddns.net/airflow'
    AIRFLOW__WEBSERVER__ENABLE_PROXY_FIX: 'True'
    _PIP_ADDITIONAL_REQUIREMENTS: ${_PIP_ADDITIONAL_REQUIREMENTS:-}
  volumes:
    - ./storage/airflow/dags:/opt/airflow/dags
    - ./storage/airflow/logs:/opt/airflow/logs
    - ./storage/airflow/plugins:/opt/airflow/plugins
  user: "${AIRFLOW_UID:-1000}:0"
  secrets:
    - sql_alchemy_conn
    - result_backend
    - machine_pass
  depends_on:
    &airflow-common-depends-on
    redis:
      condition: service_healthy
    postgres:
      condition: service_healthy

x-stuff-common:
  &stuff-common
  restart: unless-stopped
  networks:
    - ${DOCKER_NETWORK:-stuff}

services:
  nginx:
    <<: *stuff-common
    container_name: stuff-nginx
    image: nginxproxy/nginx-proxy:alpine
    hostname: nginx
    ports:
      - ${PORT_NGINX:-80}:80
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./config/nginx.conf:/etc/nginx/nginx.conf:ro
    secrets:
      - stuff_ddns_net_pem_chain
      - stuff_ddns_net_key
      - dhparam.pem

  airflow-webserver:
    <<: *stuff-common
    <<: *airflow-common
    container_name: stuff-airflow-webserver
    command: webserver
    ports:
      - ${PORT_UI_AIRFLOW:-8080}:8080
    healthcheck:
      test: ["CMD", "curl", "--fail", "http://localhost:${PORT_UI_AIRFLOW:-8080}/airflow/health"]
      interval: 10s
      timeout: 10s
      retries: 5
    depends_on:
      <<: *airflow-common-depends-on
      airflow-init:
        condition: service_completed_successfully

networks:
  stuff:
    name: ${DOCKER_NETWORK:-stuff}

secrets:
  ... <truncated> 
解决思路

1. 排查基础网络连通性

  • 验证DDNS解析:在公网环境(比如手机4G)执行nslookup stuff.ddns.net,确认返回的IP是你的公网IP,且和路由器WAN口IP一致。如果解析错误,检查NoIP客户端的运行状态,确保IP更新任务正常执行。
  • 测试端口可达性:用telnet stuff.ddns.net 443或在线端口检测工具测试80、443端口是否开放。如果端口不可达,检查路由器端口转发规则:
    • 确认转发的目标IP是Linux机器的静态内网IP,不是动态分配的;
    • 检查路由器是否开启了防火墙,是否拦截了80/443端口的入站请求;
    • 部分ISP会封禁80/443端口,可以尝试换用其他端口(比如8080/8443)测试,同时调整路由器转发和Nginx监听配置。

2. 修正Docker内部网络访问问题

Nginx容器里的upstream airflow配置的是localhost:8080,但在Docker网络中,localhost指向Nginx容器自身,而非宿主机或Airflow容器。需要修改:

  • 方案一:使用Docker服务名访问:因为Nginx和Airflow在同一个自定义网络stuff中,直接用Airflow服务名airflow-webserver代替localhost:
    upstream airflow {
        server airflow-webserver:8080;
    }
    
  • 方案二:使用宿主机内网IP:如果不想依赖Docker服务发现,也可以配置成Linux机器的静态内网IP,比如192.168.x.x:8080。

3. 调整Nginx代理配置细节

  • 开放Nginx的443端口:当前docker-compose.yml中Nginx只映射了80端口到宿主机,443端口未映射,需要添加:
    ports:
      - ${PORT_NGINX:-80}:80
      - ${PORT_NGINX_SSL:-443}:443
    
    否则路由器转发的443请求无法到达Nginx容器。
  • 修正proxy_pass路径:当前location /airflow/对应的proxy_pass http://airflow会把请求转发到http://airflow/,而Airflow的Base URL设置了/airflow前缀,需要确保路径匹配,修改为:
    location /airflow/ {
        proxy_pass http://airflow/airflow/;
        # 其他配置保持不变
    }
    
  • 检查SSL配置有效性:进入Nginx容器执行nginx -t,验证SSL证书、密钥和dhparam文件是否可读且格式正确。如果证书加载失败,Nginx无法启动443端口监听,会导致连接失败。

4. 验证Airflow服务状态

  • 进入Airflow容器执行curl http://localhost:8080/airflow/health,确认服务正常响应。如果返回失败,检查Airflow日志,确认Webserver是否正常启动。
  • 确保AIRFLOW__WEBSERVER__ENABLE_PROXY_FIX设置为True,这个配置让Airflow正确识别代理传递的请求头,生成正确的URL链接。

内容的提问来源于stack exchange,提问作者Fomalhaut -C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 17:45:43