集中 ssl 反向代理服务器的建设
一直想弄这个东东。
面临的现状是:
1、公网 ip 相当有限;
2、需要对外提供的 80/443 端口服务的内网服务器很多;
3、想要使用免费的易于部署的 ssl 证书。
实现手段是:
1、使用反向代理实现单公网 ip 单端口映射内网多台服务器;
2、使用 let’s encrypt 证书进行一处部署和更新,内网外网通用。
具体操作如下:
架设好内网反向代理服务器。在这儿用的是 nginx@freebsd 。
在这儿有个问题。如果使用了 ssl 证书的话,同时做了反向代理,那么就要在内网服务器和反向代理服务器上同样加载证书才可以。而且,如果使用 let’s encrypt 证书的话,由于它有一定周期性,还要保证在一定的周期内可以两边都自动同步。这是个麻烦事。有没有集中部署统一更新的方法呢?有。
首先,将需要进行反向代理的服务器对应的域名,都解析到反向代理服务器上。业务服务器上无论是 iis 的主机头还是 apache 的 vhost 都没关系。只要它们设置好了 server_name 就可以了。然后很重要的一点就是在反向代理服务器上设置 hosts ,将业务服务器 ip 和业务服务器需要对外的域名对应起来。
这样做的目的就是要无论内外网中,大家访问业务服务器的时候是经由反向代理服务器的,而在反向代理服务器本地,由于需要进行反向代理,所以需要通过域名来找到业务服务器,所以需要在本地添加 hosts 来覆盖掉内网 dns 服务器做的业务服务器解析。
OK,解决了这个先决的问题之后,可以开始进行反向代理和证书的设置了。
在主配置文件 nginx.conf 中,我们按域名分开不同的配置项,如:
include conf/rp_test.test.com.conf;
然后再看看 rp_test.test.com.conf 里面的配置:
server { listen 192.168.1.10:80; listen 192.168.1.10:443 ssl http2; server_name www.mydomain.com; location /.well-known/ { default_type "text/plain"; alias /usr/local/www/nginx/.well-known/; } if ($scheme = 'http') { return 301 https://www.mydomain.com$request_uri; } ssl_certificate /usr/local/etc/letsencrypt/live/www.mydomain.com/fullchain.pem; ssl_certificate_key /usr/local/etc/letsencrypt/live/www.mydomain.com/privkey.pem; ssl_stapling on; ssl_stapling_verify on; if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})"){ set $year $1; set $month $2; set $day $3; } access_log /var/log/nginx/www.mydomain.com/ssl.access.$year$month$day.log main; error_log /var/log/nginx/www.mydomain.com/ssl.error.log; location / { proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Scheme $scheme; proxy_set_header Accept-Encoding ""; proxy_set_header X-Forwarded-Ssl on; proxy_pass_header User-Agent; proxy_pass http://www.mydomain.com; proxy_redirect http:// $scheme://; sub_filter_types text/css text/xml; sub_filter http://$host $scheme://$host; sub_filter_once off; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } error_page 404 /404.html; location = /404.html { root html; } }
然后重启就可以了。
需要注意的是,如果内网有 wordpress 服务器的话,可能仍然有一些 js 之类的走 http 不能被 https 正常加载,怎么办?有一个 SSL Insecure Content Fixer 或 really-simple-ssl 的插件可以解决这个问题。
如此,就大功告成了~
Edit:
血的教训啊…
在使用命令行申请证书的时候:
certbot certonly --email root@mydomain.com --webroot -w /usr/local/www/nginx -d www.mydomain.com
里面的 -w 对应的值要千万和配置项中的 location /.well-known 中对应的一致。否则会显示如下的错误:
Failed authorization procedure. www.mydomain.com (http-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://www.mydomain.com/.well-known/acme-challenge/hPixJOxDwVHzxw-W625Yc6H9-oWN6yPccWkrwM_KJDJc [8.8.8.8]: 404 IMPORTANT NOTES: - The following errors were reported by the server: Domain: www.mydomain.com Type: unauthorized Detail: Invalid response from http://www.mydomain.com/.well-known/acme-challenge/hPixJOxDwVHzxw-W625Yc6H9-oWN6yPccWkrwM_KJDJc [8.8.8.8]: 404 To fix these errors, please make sure that your domain name was entered correctly and the DNS A record(s) for that domain contain(s) the right IP address.
Edit(20200409):
当初想得太复杂,其实很简单,在反代上统一更新证书,然后域名都解析到反代,反代上配置代理内网 ip 就好了。