Why this setup breaks
There is a chain like this: several domains are proxied by nginx to frps, and frps then forwards traffic to frpc for intranet access.
The problem appears in frps’s HTTPS intranet mode: it does not use the Host header, only the address in the URI. Because of that, proxy_pass cannot simply point to 127.0.0.1.
One workaround is to point proxy_pass to something like sub1.xxx.com and map that name to 127.0.0.1 in /etc/hosts. But nginx does not use /etc/hosts when resolving the hostname in proxy_pass, so that method does not take effect.
Use a local DNS resolver instead
The practical fix is to run a small DNS service on the machine and let nginx resolve the domain through it.
Install dnsmasq
apt-get install dnsmasq
During installation, it may fail because port 53 is already occupied by systemd-resolved. The confusing part is that even though systemd-resolved is running, it still does not make /etc/hosts work for nginx proxy_pass in this case.
So the first step is to stop systemd-resolved from binding to port 53.
Check who is using port 53 first:
lsof -i :53
After confirming that systemd-resolved is the one holding the port, edit /etc/systemd/resolved.conf:
[Resolve]
DNS=8.8.8.8
#FallbackDNS=
#Domains=
#LLMNR=no
#MulticastDNS=no
#DNSSEC=no
#DNSOverTLS=no
#Cache=yes
DNSStubListener=no
#ReadEtcHosts=yes
Only DNS and DNSStubListener need to be enabled here, and DNSStubListener should be set to no.
Then link /run/systemd/resolve/resolv.conf to /etc/resolv.conf:
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
Reboot the server after that:
sudo reboot
Once the machine comes back up, continue installing and start dnsmasq:
systemctl start dnsmasq.service
Enable it at boot as well:
systemctl enable dnsmasq.service
Configure dnsmasq
Create a resolver file for upstream DNS servers:
vi /etc/resolv.dnsmasq
nameserver 114.114.114.114
nameserver 8.8.8.8
Next, edit the dnsmasq configuration and enable addn-hosts and resolv-file:
vi /etc/dnsmasq.conf
# If you don't want dnsmasq to read /etc/hosts, uncomment the
# following line.
#no-hosts
# or if you want it to read another file, as well as /etc/hosts, use
# this.
找到这里配置下面
addn-hosts
addn-hosts=/etc/dnsmasqhosts
# Change this line if you want dns to get its upstream servers from
# somewhere other that /etc/resolv.conf
这里配置resolv.dnsmasq文件
resolv-file=/etc/resolv.dnsmasq
Now add the custom internal domain mapping:
vi /etc/dnsmasqhosts
127.0.0.1 xxx.shellingford.cn
Restart the service after saving the files:
systemctl restart dnsmasq.service
Point nginx at the local resolver
In the nginx configuration, the important part is to set resolver to 127.0.0.1, otherwise nginx will not use the local DNS service.
location ^~ / {
proxy_pass https://$host:8101;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
add_header X-Cache $upstream_cache_status;
add_header Strict-Transport-Security "max-age=31536000";
add_header Cache-Control no-cache;
resolver 127.0.0.1;
proxy_ssl_server_name on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
With this in place, nginx can resolve the custom domain through dnsmasq, and the reverse proxy path to the local service works as expected.