前言
受同一个系统中多个 TCP 服务进程无法绑定同一个端口这个概念的影响,误以为在nginx也无法配置通过同一个端口无法转发到多个不同域名的后端服务,于是本文使用配置来验证,实际是完全可以在同一端口上配置转发多个服务,且无需依赖不同协议。
如果两个 TCP 服务进程同时绑定的 IP 地址和端口都相同,那么执行 bind() 时候就会出错,错误是“Address already
in use”。
原理
其核心原理是通过 请求特征区分流量(如域名、路径、请求头),而非依赖不同协议或端口。以下是具体实现方式和配置示例:
Nginx 的 server 块和 location 块支持根据以下特征区分请求:
域名(server_name):不同域名访问同一端口时,Nginx 根据 Host 头分发到不同服务。
路径(location):同一域名的不同 URL 路径分发到不同服务。
协议:严格来说,HTTP 和 HTTPS 协议需要不同端口(如 80 和 443),但可以在同一端口上通过协议升级(如 WebSocket)或同一协议下的不同路由逻辑实现多服务。
配置
使用同一个端口监听转发到不同服务,其实有两种配置,①是通过不同域名;②基于路径(URL 路由);
不同域名
通过不同域名(如 lvan.service1.*** 和 lvan.service2.***)在同一端口(如 80)访问不同服务。
在nginx.conf配置
http {
# 服务1:通过 lvan.service1.*** 访问
server {
listen 80;
server_name lvan.service1.***; # 域名1
location / {
proxy_pass http://localhost:3000; # 转发到服务1
}
}
# 服务2:通过 lvan.service2.*** 访问
server {
listen 80;
server_name lvan.service2.***; # 域名2
location / {
proxy_pass http://localhost:4000; # 转发到服务2
}
}
}
基于路径(URL 路由)
通过同一域名和端口的不同路径(如 /app1 和 /app2)访问不同服务。
http {
server {
listen 80;
server_name example.***;
# 服务1:路径 /app1
location /app1/ {
proxy_pass http://localhost:3000/; # 末尾的 / 会移除 /app1/
}
# 服务2:路径 /app2
location /app2/ {
proxy_pass http://localhost:4000/; # 末尾的 / 会移除 /app2/
}
# 默认路由(可选)
location / {
root /var/www/html; # 静态资源或其他默认服务
}
}
}
注意:proxy_pass 末尾的 / 会移除原始路径前缀(如 /app1/api 转发为 /api)。
路径匹配优先级:精确路径(=)> 正则路径(~)> 普通路径。
补充
还可以通过混合协议(HTTP + WebSocket)。在同一端口(如 80)同时处理 HTTP 请求和 WebSocket 连接(需协议升级)。
http {
server {
listen 80;
server_name example.***;
# HTTP 服务
location /api {
proxy_pass http://localhost:3000;
}
# WebSocket 服务
location /ws {
proxy_pass http://localhost:4000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; # 协议升级头
proxy_set_header Connection "Upgrade";
}
}
}
注意:
WebSocket 本质是 HTTP 协议升级,仍使用同一端口。
需配置 Upgrade 和 Connection 头支持协议切换。
总之
同一端口部署多服务的核心:利用 Nginx 的请求分发能力,根据域名、路径、协议升级等特征区分流量。