Docker中Nginx反向代理访问静态站点错误加载Appwrite服务
问题成因
两个核心配置错误导致请求被错误转发到Appwrite服务:
- Nginx默认虚拟主机匹配逻辑问题:Nginx对同一监听端口的请求,会优先匹配
server_name和请求Host头一致的server块;如果没有匹配项,会直接把请求发给该端口下第一个定义的server块作为默认响应。你的配置中第一个server块(Appwrite反代配置)同时监听了80、443端口,而两个静态站点的server块仅配置了80端口监听:- 所有HTTPS协议(443端口)访问domain1.com、domain2.com的请求,没有对应匹配的server块,直接命中默认的Appwrite反代逻辑
- 如果请求带了www前缀、或者Host头和配置的
server_name不完全匹配,80端口的请求也会落到默认的反代块返回Appwrite内容
- Docker卷挂载路径错误:Compose配置里把本地
./domain1.com、./domain2.com两个目录都直接挂载到容器内/var/www路径,后挂载的目录会覆盖前一个,且容器内根本不存在Nginx配置中写的/var/www/domain1.com、/var/www/domain2.com路径,就算请求命中静态站点的server块,也会因为找不到静态文件触发错误,进一步兜底到反代逻辑。
修复步骤
- 修正Compose文件的卷挂载配置,把静态目录挂载到和Nginx配置对应的子路径,修改后nginx服务的volumes段如下:
volumes: - ./config:/etc/nginx - appwrite-certificates:/etc/ssl/private - ./domain2.com:/var/www/domain2.com - ./domain1.com:/var/www/domain1.com
调整Nginx配置,修正默认主机规则、补全匹配逻辑:
- 移除废弃的
ssl on;写法,改用listen 443 ssl;的标准配置,同时移除不安全的TLSv1、TLSv1.1协议支持 - 显式添加80、443端口的默认兜底server块,把未匹配到对应域名的请求直接返回404/444,避免落到Appwrite反代块
- 为两个静态站点补全常见域名别名(比如www前缀),避免Host不匹配导致的错误转发
参考修改后的完整Nginx配置:
- 移除废弃的
events { worker_connections 1024; } http { # 443端口兜底,非api域名的HTTPS请求直接断开连接 server { listen 443 ssl default_server; ssl_certificate /etc/ssl/private/api.domain.com/cert.pem; ssl_certificate_key /etc/ssl/private/api.domain.com/privkey.pem; return 444; } # Appwrite反代配置 server { listen 80; listen 443 ssl; ssl_certificate /etc/ssl/private/api.domain.com/cert.pem; ssl_certificate_key /etc/ssl/private/api.domain.com/privkey.pem; ssl_session_cache builtin:1000 shared:SSL:10m; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4; ssl_prefer_server_ciphers on; server_name api.domain.com; location / { 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 Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; proxy_pass http://appwrite; } location /v1/realtime { proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; 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 Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; proxy_pass http://appwrite-realtime; proxy_http_version 1.1; proxy_connect_timeout 7d; proxy_send_timeout 7d; proxy_read_timeout 7d; } } # 80端口兜底,未匹配域名直接返回404 server { listen 80 default_server; return 404; } server { listen 80; root /var/www/domain1.com; server_name domain1.com www.domain1.com; index index.html index.htm index.nginx-debian.html; location / { try_files $uri $uri/ =404; } } server { listen 80; root /var/www/domain2.com; server_name domain2.com www.domain2.com; index index.html index.htm index.nginx-debian.html; location / { try_files $uri $uri/ =404; } } }
- 重载配置生效,在Compose文件所在目录执行以下命令:
docker compose up -d docker compose exec nginx nginx -t docker compose exec nginx nginx -s reload
执行
nginx -t是为了提前校验配置语法有没有错误,避免重载失败导致Nginx挂掉。如果后续需要给两个静态站点开启HTTPS,只需要给对应的server块添加443 ssl监听、配置对应证书路径即可。
内容的提问来源于stack exchange,提问作者StreY
相关产品推荐
相关产品推荐

