起源
我只是想让DDNS访问和内网访问时都能使用正确的证书,但是uhttpd似乎不支持对模糊的接口指定专用的证书。因此我就想到了反向代理之神 nginx 。对于方式,不能使用直接的网站服务模式,因为其中包含很多 uci 控制命令,nginx 无法识别。因此工作方式为 uhttpd 运行处理 uci ,nginx 接受外部流量并进行转发。
思路
准备让uhttpd监听在一个偏僻的端口,同时为了防止好事者乱访问,仅允许本地访问,让nginx的流量转发即可。
开整
也不多说别的了,这个肯定得做:
opkg update
opkg install nginx
我们先让 uhttpd 监听在一个仅可本地访问的不常用端口上,而且关掉它本身的 HTTPS 跳转。可以按照如下指示编辑 uhttpd 文件。
- /etc/config/uhttpd 内容
config uhttpd 'main'
list listen_http '127.0.0.1:11480' # 这是uhttpd监听的端口,最好保持本地访问
option redirect_https '0' # 废物uhttpd不配处理SSL,让nginx代劳
option home '/www'
option rfc1918_filter '1'
option max_requests '50'
option max_connections '100'
option cert '/etc/uhttpd.crt'
option key '/etc/uhttpd.key'
option cgi_prefix '/cgi-bin'
list lua_prefix '/cgi-bin/luci=/usr/lib/lua/luci/sgi/uhttpd.lua'
option script_timeout '3600'
option network_timeout '30'
option http_keepalive '20'
option tcp_keepalive '1'
option ubus_prefix '/ubus'
list ucode_prefix '/cgi-bin/luci=/usr/share/ucode/luci/uhttpd.uc'
config cert 'defaults'
option days '730'
option key_type 'ec'
option bits '2048'
option ec_curve 'P-256'
option country 'ZZ'
option state 'Somewhere'
option location 'Unknown'
option commonname 'OpenWrt'
好的,接下来就可以配置 nginx 了,这是nginx.conf。可以参考如下内容:
- /etc/nginx/nginx.conf
user nobody nogroup; # 这里注意一下,OP中不是nobody:nobody形式,而是nobody:nogroup形式,使用特定不可登录用户更安全。
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name your.domain 192.168.114.1; # 这里设置你的其它登录别名
return 301 https://your.domain$request_uri; # 这里带URI转发,防止别人第一次必回首页而红温
}
server {
listen 443 ssl http2;
server_name op.ncc.local;
ssl_certificate /etc/nginx/ssl/path;
ssl_certificate_key /etc/nginx/ssl/path;
location / {
proxy_pass http://127.0.0.1:11480; # 这里放uhttp的配置监听端口
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;
}
}
}
我则是配置了 SNI 来实现不同域名给不同证书:
user nobody nogroup;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name op.ncc.local 192.168.114.1;
return 301 https://op.ncc.local$request_uri;
}
server {
listen 443 ssl http2;
server_name op.ncc.local;
ssl_certificate /etc/nginx/ssl-crts/op.ncc.local/op.crt;
ssl_certificate_key /etc/nginx/ssl-crts/op.ncc.local/op.key;
location / {
proxy_pass http://127.0.0.1:11480;
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;
}
}
server {
listen 80;
server_name nancunchild.zapto.org;
return 301 https://nancunchild.zapto.org$request_uri;
}
server {
listen 443 ssl http2;
server_name nancunchild.zapto.org;
ssl_certificate /etc/nginx/ssl-crts/nancunchild.zapto.org/op.crt;
ssl_certificate_key /etc/nginx/ssl-crts/nancunchild.zapto.org/op.key;
location / {
proxy_pass http://127.0.0.1:11480;
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;
}
}
}
题外话
感觉这个真的不难,也就是nginx不会用,看来这个东西确实有一点学习曲线。对了,关于校内DDNS 需要带SSL证书,好像不好找到免费的,毕竟那个bot只给公网IP玩。所以我找到的是no-ip的动态域名提供商,每年得给他几美刀充值最便宜的套餐来换动态域名SSL证书。
而且注意,不知道什么原因,直接在OP里面下载的DDNS插件似乎没有针对no-ip的脚本,但是你可以在opkg里找到可以单独安装的no-ip脚本,安装后就多出no-ip的选择项。