Ubuntu多非标准端口服务的HTTP转HTTPS应用层实现问题
嘿,我来帮你搞定这个问题!你之前用反向代理只跑通一个服务的情况太常见了,多半是配置没做到位。下面我就用最常用的Nginx(当然也会提更省心的Caddy)给你详细讲怎么在应用层实现多个非标准端口服务的HTTP转HTTPS,完全不用碰防火墙规则。
核心思路
咱们的核心逻辑是用反向代理作为HTTPS入口:所有外部的HTTPS请求先打到反向代理服务器(比如Nginx),由它处理SSL证书验证、加密解密,然后把请求转发到后端各个服务的HTTP端口。这样后端服务完全不用修改,只需要专注于业务逻辑就行。
具体实现步骤(以Nginx为例)
1. 安装Nginx
先确保你的Ubuntu服务器上装了Nginx:
sudo apt update && sudo apt install nginx
2. 获取SSL证书(生产环境必备)
HTTPS离不开合法的SSL证书,推荐用Let's Encrypt的免费证书,安装证书工具:
sudo apt install certbot python3-certbot-nginx
然后申请证书(替换成你的域名):
sudo certbot --nginx -d your-domain.com -d serviceA.your-domain.com -d serviceB.your-domain.com
这个命令会自动帮你配置Nginx的SSL参数,还能设置自动续期证书,非常省心。
3. 配置多服务转发
这是最关键的一步,打开Nginx的站点配置文件(比如新建一个/etc/nginx/sites-available/multi-services.conf),根据你的需求选下面两种配置方式:
方式一:子域名区分服务
如果每个服务用独立的子域名(比如serviceA.your-domain.com对应8080端口的服务,serviceB.your-domain.com对应9090端口的服务),配置如下:
# 服务A的HTTPS转发配置 server { listen 443 ssl; server_name serviceA.your-domain.com; # certbot自动生成的证书路径,不用改 ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; location / { proxy_pass http://localhost:8080; # 后端服务A的HTTP端口 # 传递必要的请求头给后端服务 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; } } # 服务B的HTTPS转发配置 server { listen 443 ssl; server_name serviceB.your-domain.com; ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; location / { proxy_pass http://localhost:9090; # 后端服务B的HTTP端口 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; } } # 强制所有HTTP请求跳转到HTTPS(可选但推荐) server { listen 80; server_name serviceA.your-domain.com serviceB.your-domain.com; return 301 https://$host$request_uri; }
方式二:同一域名不同路径区分服务
如果不想用多个子域名,也可以用同一个域名的不同路径(比如your-domain.com/serviceA对应8080,your-domain.com/serviceB对应9090),配置如下:
server { listen 443 ssl; server_name your-domain.com; ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; # 服务A路径转发(注意结尾的斜杠,避免路径拼接问题) location /serviceA/ { proxy_pass http://localhost:8080/; 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; } # 服务B路径转发 location /serviceB/ { proxy_pass http://localhost:9090/; 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; } } # 强制HTTP转HTTPS server { listen 80; server_name your-domain.com; return 301 https://$host$request_uri; }
4. 验证配置并重启Nginx
配置完后先检查有没有语法错误:
sudo nginx -t
如果提示test is successful,就重启Nginx生效:
sudo systemctl restart nginx
为什么你之前只一个服务工作?
大概率是这两个原因:
- 配置冲突:多个
server块监听了同一个端口和域名,Nginx只会匹配第一个符合条件的server块,导致其他服务的配置失效。解决办法是给每个server块指定明确的server_name。 - Location规则优先级:如果用路径区分服务,更通用的规则(比如
location /)放在了前面,会匹配所有请求,导致后面的特定路径规则不生效。解决办法是把更精确的路径规则放在前面。
更省心的替代方案:Caddy
如果你觉得Nginx配置有点繁琐,可以试试Caddy——它会自动管理SSL证书,配置语法更简洁。安装Caddy后,只需要在/etc/caddy/Caddyfile里写:
# 子域名方式 serviceA.your-domain.com { reverse_proxy localhost:8080 } serviceB.your-domain.com { reverse_proxy localhost:9090 } # 路径方式(可选) # your-domain.com { # reverse_proxy /serviceA/* localhost:8080 # reverse_proxy /serviceB/* localhost:9090 # }
然后重启Caddy就行,它会自动申请证书并续期,完全不用手动处理SSL的细节。
注意事项
- 确保后端服务只监听
localhost或者内网IP,不要直接暴露到公网,这样只有反向代理能访问它们,安全性更高。 - 如果没有公网域名,测试时可以用自签名证书,但浏览器会提示不安全,生产环境一定要用合法证书。
备注:内容来源于stack exchange,提问作者idk_im_a_junior

