徹底解決 Nginx 502 錯誤與跨域困擾:從根源到優化的全流程指導
引言
前幾天公司讓搭建一個 Nexus 做一個私服。
先簡單介紹下為什么要搭建這個服務:
Nexus 是一個強大而靈活的倉庫管理工具,廣泛應用于 DevOps 和軟件開發團隊。無論是托管內部構件、代理公共倉庫,還是作為 Docker 鏡像倉庫,Nexus 都能提供高效的解決方案。同時,它與 CI/CD 工具集成良好,是現代軟件開發流程中不可或缺的組件。
最主要的是可以將我們開發相關的包放進去。
這邊的 Nexus 是使用 Docker-Compose 直接部署了一個。
version: '3'
services:
nexus3:
restart: unless-stopped
image: sonatype/nexus3:latest
build: .
container_name: nexus3
environment:
- TZ=Asia/Shanghai
ports:
- 8081:8081
volumes:
- /data/nexus/data:/nexus-data
訪問的時候,直接 IP 地址加端口。但是這樣的方式在瀏覽器中不是很友好,于是加上了域名解析,使用域名加端口,哈哈,很有意思吧。但是后面又覺得不安全,決定使用 SSL 證書訪問,那就整唄。
開始
決定使用 Yum 在本地安裝一個算了,創建一個 /etc/nginx/certs 目錄,然后把 SSL 證書放進去。
然后這邊主要是說一下 Nginx 的配置:
# /home/user/nginx/conf/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
# 啟用 Gzip 壓縮
gzip on;
gzip_disable "msie6";
# 定義后端服務的 upstream
upstream backend {
server 8.209.247.131:8081; # 后端服務地址
}
# HTTP 服務器 - 處理 ACME Challenge 并重定向到 HTTPS
server {
listen 80;
server_name nexus.test.com;
# 配置 ACME Challenge 的路徑
location /.well-known/acme-challenge/ {
root /usr/share/nginx/html;
}
# 將所有其他 HTTP 請求重定向到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS 服務器
server {
listen 443 ssl;
server_name nexus.test.com;
# SSL 證書和私鑰路徑
ssl_certificate /etc/nginx/certs/test.com.pem;
ssl_certificate_key /etc/nginx/certs/test.com.key;
# SSL 協議和加密套件配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
# 啟用 HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# SSL 會話緩存和超時
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# 日志配置
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
# 反向代理設置
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
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;
# 支持 WebSocket
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 可選:額外的安全頭部
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
}
# 可選:其他服務器塊或配置
}
然后重載上面的配置 :
systemctl reload nginx
訪問:
圖片
看起來是可以訪問到,但是沒有訪問到后端服務 Nexus,這是什么情況呢。
來看下日志吧,看看有什么線索沒:
10.23.45.67 - - [31/Dec/2024:10:01:09 +0800] "GET /favicon.ico HTTP/1.1" 502 559 "https://nexus.test.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" "-"
12.34.56.78 - - [31/Dec/2024:10:08:38 +0800] "GET /favicon.ico HTTP/1.1" 502 559 "https://nexus.test.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" "-"
15.67.89.90 - - [31/Dec/2024:10:13:17 +0800] "GET /favicon.ico HTTP/1.1" 502 559 "https://nexus.test.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" "-"
2024/12/31 10:00:37 [error] 24090#0: *23 connect() failed (110: Connection timed out) while connecting to upstream, client: 10.23.45.67, server: nexus.test.com, request: "GET /favicon.ico HTTP/1.1", upstream: "http://12.45.67.89:8081/favicon.ico", host: "nexus.test.com", referrer: "https://nexus.test.com/"
2024/12/31 10:08:38 [error] 24226#0: *29 connect() failed (110: Connection timed out) while connecting to upstream, client: 12.34.56.78, server: nexus.test.com, request: "GET /favicon.ico HTTP/1.1", upstream: "http://23.56.78.90:8081/favicon.ico", host: "nexus.test.com", referrer: "https://nexus.test.com/"
2024/12/31 10:13:17 [error] 24226#0: *33 connect() failed (110: Connection timed out) while connecting to upstream, client: 15.67.89.90, server: nexus.test.com, request: "GET /favicon.ico HTTP/1.1", upstream: "http://34.67.89.12:8081/favicon.ico", host: "nexus.test.com", referrer: "https://nexus.test.com/"
還是看不出來具體的錯誤,大佬們有經驗的可以先思考下。
經過一番排查,誤以為是和 VPN 有關系,于是,想了半天,要不然試試 127.0.0.1。
試下,我這里選擇更改我的 upstream 的地址:
# /home/user/nginx/conf/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
# 啟用 Gzip 壓縮
gzip on;
gzip_disable "msie6";
# 定義后端服務的 upstream
upstream backend {
server 127.0.0.1:8081; # 后端服務地址
}
# HTTP 服務器 - 處理 ACME Challenge 并重定向到 HTTPS
server {
listen 80;
server_name nexus.test.com;
# 配置 ACME Challenge 的路徑
location /.well-known/acme-challenge/ {
root /usr/share/nginx/html;
}
# 將所有其他 HTTP 請求重定向到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS 服務器
server {
listen 443 ssl;
server_name nexus.test.com;
# SSL 證書和私鑰路徑
ssl_certificate /etc/nginx/certs/test.com.pem;
ssl_certificate_key /etc/nginx/certs/test.com.key;
# SSL 協議和加密套件配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
# 啟用 HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# SSL 會話緩存和超時
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# 日志配置
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
# 反向代理設置
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
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;
# 支持 WebSocket
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 可選:額外的安全頭部
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
}
# 可選:其他服務器塊或配置
}
搞笑了,這波操作,屬實是給我弄的不想說什么了,哈哈,但是又有新的問題了,我們接著看
又有新的錯誤了:
圖片
排查了會兒,新的問題是 跨域問題(CORS)。
1. "Uncaught SecurityError" 表明瀏覽器阻止了對 nexus.test.com 的跨域訪問。
2. Blocked a frame with origin 表示 Nexus 的前端代碼試圖訪問另一個域或協議(可能是 HTTP 而非 HTTPS,或子域不匹配)。
原因分析
1.協議或域名不一致:
? Nexus 的資源(如靜態文件或 API 請求)可能仍指向 HTTP,而您使用的是 HTTPS。
? Nexus 的前端代碼試圖訪問外部的資源,但瀏覽器將其視為跨域。
2.Nginx 配置問題:
? Nginx 的反向代理可能沒有正確設置 CORS 相關頭部,導致資源加載失敗。
解決方法
更新 Nginx 配置以支持 CORS
為 Nginx 添加 CORS 支持,允許 Nexus 的前端和 API 資源在同一個域下工作。
在 Nginx 的 location / 配置中,添加以下內容:
location / {
·····
# 添加 CORS 頭部
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
add_header Access-Control-Allow-Headers "Origin, Authorization, Accept, Content-Type";
·····
}
重新加載 Nginx:
systemctl reload nginx
再次訪問:
圖片
可以看到,沒有問題了。
結語
經過這一次的故障排查,又加深了我對 Nginx 的學習。
因為啥呢,工作這邊很少會有去部署一個 Nginx,然后去配置相應的參數,真的很少。但是當有這種情況,你又不能說不會,或者不干。在這個排查的過程中,當時排查的真的有點泄氣,但是總歸還是過來了。