| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- user root;
- worker_processes 1;
- #error_log logs/error.log;
- #error_log logs/error.log notice;
- error_log logs/warn.log warn;
- pid logs/nginx.pid;
- events {
- worker_connections 1024;
- }
- http {
- # DNS 服务器地址
- resolver 1.1.1.1 ipv6=off;
- include mime.types;
- default_type text/html;
- sendfile on;
- #tcp_nopush on;
- #keepalive_timeout 0;
- keepalive_timeout 60;
- keepalive_requests 1024;
- server_tokens off;
- more_clear_headers Server;
- # 限流配置
- limit_req_log_level warn;
- limit_req_zone $binary_remote_addr zone=reqip:16m rate=100r/s;
- limit_req zone=reqip burst=200 nodelay;
- # 代理日志(分隔符 \t)
- log_format log_proxy
- '$time_iso8601 $remote_addr $request_time '
- '$request_length $bytes_sent '
- '$request_method $_proto $proxy_host $request_uri $status '
- '$http_user_agent'
- ;
- # 普通日志
- log_format log_access
- '$time_iso8601 $remote_addr $request_time '
- '$request_method $uri $http_host $status '
- '$http_user_agent'
- ;
- access_log logs/access.log log_access buffer=64k flush=1s;
- # 缓冲区配置
- #(设置过低某些网站无法访问)
- proxy_buffer_size 16k;
- proxy_buffers 4 32k;
- proxy_busy_buffers_size 64k;
- proxy_send_timeout 10s;
- # 代理缓存配置
- proxy_cache_path cache
- levels=1:2
- keys_zone=my_cache:8m
- max_size=10g
- inactive=6h
- use_temp_path=off;
- # SSL 双证书
- include include/cert.conf;
- ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
- ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE+AES128:RSA+AES128:ECDHE+AES256:RSA+AES256:ECDHE+3DES:RSA+3DES;
- ssl_prefer_server_ciphers on;
- ssl_session_cache shared:SSL:10m;
- ssl_session_timeout 5m;
- proxy_cache my_cache;
- proxy_http_version 1.1;
- proxy_ssl_server_name on;
- underscores_in_headers on;
- merge_slashes off;
- # 非内置域名的编码(将 `.` 替换成 `-dot-`)
- # TODO: 由于 nginx map 不支持字符串替换,暂时先这么实现。。。
- map $_rhost $_rhost_enc_ext {
- volatile;
- '~^([\w-]+)\.(\w+)$' '$1-dot-$2';
- '~^([\w-]+)\.([\w-]+)\.(\w+)$' '$1-dot-$2-dot-$3';
- '~^([\w-]+)\.([\w-]+)\.([\w-]+)\.(\w+)$' '$1-dot-$2-dot-$3-dot-$4';
- }
- # 非内置域名的解码(将 `-dot-` 替换成 `.`)
- # TODO: 效率低而且级数有限,下次改成 lua 实现
- map $_ext_src $_ext_dst {
- volatile;
- '~^([\w-]+?)-dot-([\w-]+?)-dot-([\w-]+?)-dot-([\w-]+?)-dot-([\w-]+?)-dot-(\w+)$'
- '$1.$2.$3.$4.$5.$6';
- '~^([\w-]+?)-dot-([\w-]+?)-dot-([\w-]+?)-dot-([\w-]+?)-dot-(\w+)$'
- '$1.$2.$3.$4.$5';
- '~^([\w-]+?)-dot-([\w-]+?)-dot-([\w-]+?)-dot-(\w+)$'
- '$1.$2.$3.$4';
- '~^([\w-]+?)-dot-([\w-]+?)-dot-(\w+)$'
- '$1.$2.$3';
- '~^([\w-]+?)-dot-(\w+)$'
- '$1.$2';
- }
- map $_vhost $_vhost_dec_ext {
- volatile; #.example.com
- '~^(?<_ext_src>[^.]+)\.ext\.[\w-]+\.\w+$' $_ext_dst;
- }
- # 虚拟域名 -> 真实域名
- map $_vhost $_vhost_to_rhost {
- volatile;
- hostnames;
- include include/vhost-rhost.map;
- }
- # 真实域名 -> 虚拟域名
- map $_rhost $_rhost_to_vhost {
- volatile;
- hostnames;
- include include/rhost-vhost.map;
- }
- # TODO: 由于 hostnames 无法获取 * 部分,暂时先这样获取子域
- # *.com -> *
- map $_rhost $_rhost_slice_0 {
- volatile;
- '~^(.+?)\.\w+$' $1;
- }
- # *.google.com -> *
- map $_rhost $_rhost_slice_1 {
- volatile;
- '~^(.+?)\.(?:[\w-]+\.){1}\w+$' $1;
- }
- # *.google.com.hk -> *
- map $_rhost $_rhost_slice_2 {
- volatile;
- '~^(.+?)\.(?:[\w-]+\.){2}\w+$' $1;
- }
- # *.wk -> *
- map $_vhost $_vhost_slice_0 {
- volatile; #.example.com
- '~^(.+?)\.\w+\.[\w-]+\.\w+$' $1;
- }
- # *.m.wk -> *
- map $_vhost $_vhost_slice_1 {
- volatile; #.example.com
- '~^(.+?)\.(?:[\w-]+\.){1}\w+\.[\w-]+\.\w+$' $1;
- }
- ##########
- # 静态资源站点
- server {
- include include/host-root.conf;
- root ../www;
- charset utf-8;
- add_header cache-control max-age=300;
- add_header strict-transport-security 'max-age=99999999; includeSubDomains; preload';
- # 需要编译 ngx_brotli 模块(参考 setup.sh)
- brotli_static on;
- }
- # 内置站点代理
- # 格式为 https://[sub.]alias.example.com/path/to/?query
- server {
- include include/host-wild.conf;
- location / {
- set $_vhost $host;
- set $_site $_vhost_to_rhost;
- if ($_site = '') {
- return 404 "unknown site";
- }
- include proc-hdr.conf;
- # 非 JS 发送的请求,返回安装 ServiceWorker 的页面
- # 该请求为首次访问时发起,后续请求会被 SW 拦截并带上 JS 标记
- if ($_hasSw = '0') {
- rewrite ^ /__setup.html;
- }
- set $_proto 'https';
- if ($_isHttp = '1') {
- set $_proto 'http';
- }
- if ($_port) {
- set $_port ':$_port';
- }
- # CORS preflight
- if ($request_method = 'OPTIONS') {
- more_set_headers
- 'access-control-allow-origin: $_acao'
- 'access-control-allow-Methods: GET, POST, PUT, DELETE, HEAD, OPTIONS'
- 'access-control-allow-Headers: $http_Access_Control_Request_Headers'
- 'access-control-max-Age: 1728000'
- ;
- return 204;
- }
- # return 200 "[debug]
- # request_uri: $request_uri
- # host: $host
- # isHttp: $_isHttp
- # uri: $uri
- # args: $args
- # is_args: $is_args
- # _ref: $_ref
- # _ori: $_ori
- # _hasSw: $_hasSw
- # proxy: $_proto://$_site$_port;
- # ";
- access_log logs/proxy.log log_proxy buffer=64k flush=1s;
- proxy_pass $_proto://$_site$_port;
- # 将返回头 set-cookie 中的 domain 部分转换成我们的虚拟域名
- proxy_cookie_domain ~^\.?(?<_rhost>.*)$ $_rhost_to_vhost;
- }
- location = /__setup.html {
- internal;
- brotli_static on;
- charset utf-8;
- root ../www;
- etag off;
- more_clear_headers Accept-Ranges Last-Modified;
- }
- # 由于 ServiceWorker 脚本必须位于同源站点,
- # 因此为了减少重复加载,此处只返回实际脚本的引用。
- location = /__sw.js {
- add_header cache-control max-age=9999999;
- include include/x-js.conf;
- }
- }
- # 测试案例(暂未完成)
- #include test.conf;
- }
|