nginx.conf 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. user root;
  2. worker_processes 1;
  3. #error_log logs/error.log;
  4. #error_log logs/error.log notice;
  5. error_log logs/warn.log warn;
  6. pid logs/nginx.pid;
  7. events {
  8. worker_connections 1024;
  9. }
  10. http {
  11. # DNS 服务器地址
  12. resolver 1.1.1.1 ipv6=off;
  13. include mime.types;
  14. default_type text/html;
  15. sendfile on;
  16. #tcp_nopush on;
  17. #keepalive_timeout 0;
  18. keepalive_timeout 60;
  19. keepalive_requests 1024;
  20. server_tokens off;
  21. more_clear_headers Server;
  22. # 限流配置
  23. limit_req_log_level warn;
  24. limit_req_zone $binary_remote_addr zone=reqip:16m rate=100r/s;
  25. limit_req zone=reqip burst=200 nodelay;
  26. # 代理日志(分隔符 \t)
  27. log_format log_proxy
  28. '$time_iso8601 $remote_addr $request_time '
  29. '$request_length $bytes_sent '
  30. '$request_method $_proto $proxy_host $request_uri $status '
  31. '$http_user_agent'
  32. ;
  33. # 普通日志
  34. log_format log_access
  35. '$time_iso8601 $remote_addr $request_time '
  36. '$request_method $uri $http_host $status '
  37. '$http_user_agent'
  38. ;
  39. access_log logs/access.log log_access buffer=64k flush=1s;
  40. # 缓冲区配置
  41. #(设置过低某些网站无法访问)
  42. proxy_buffer_size 16k;
  43. proxy_buffers 4 32k;
  44. proxy_busy_buffers_size 64k;
  45. proxy_send_timeout 10s;
  46. # 代理缓存配置
  47. proxy_cache_path cache
  48. levels=1:2
  49. keys_zone=my_cache:8m
  50. max_size=10g
  51. inactive=6h
  52. use_temp_path=off;
  53. # SSL 双证书
  54. include include/cert.conf;
  55. ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  56. 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;
  57. ssl_prefer_server_ciphers on;
  58. ssl_session_cache shared:SSL:10m;
  59. ssl_session_timeout 5m;
  60. proxy_cache my_cache;
  61. proxy_http_version 1.1;
  62. proxy_ssl_server_name on;
  63. underscores_in_headers on;
  64. merge_slashes off;
  65. # 非内置域名的编码(将 `.` 替换成 `-dot-`)
  66. # TODO: 由于 nginx map 不支持字符串替换,暂时先这么实现。。。
  67. map $_rhost $_rhost_enc_ext {
  68. volatile;
  69. '~^([\w-]+)\.(\w+)$' '$1-dot-$2';
  70. '~^([\w-]+)\.([\w-]+)\.(\w+)$' '$1-dot-$2-dot-$3';
  71. '~^([\w-]+)\.([\w-]+)\.([\w-]+)\.(\w+)$' '$1-dot-$2-dot-$3-dot-$4';
  72. }
  73. # 非内置域名的解码(将 `-dot-` 替换成 `.`)
  74. # TODO: 效率低而且级数有限,下次改成 lua 实现
  75. map $_ext_src $_ext_dst {
  76. volatile;
  77. '~^([\w-]+?)-dot-([\w-]+?)-dot-([\w-]+?)-dot-([\w-]+?)-dot-([\w-]+?)-dot-(\w+)$'
  78. '$1.$2.$3.$4.$5.$6';
  79. '~^([\w-]+?)-dot-([\w-]+?)-dot-([\w-]+?)-dot-([\w-]+?)-dot-(\w+)$'
  80. '$1.$2.$3.$4.$5';
  81. '~^([\w-]+?)-dot-([\w-]+?)-dot-([\w-]+?)-dot-(\w+)$'
  82. '$1.$2.$3.$4';
  83. '~^([\w-]+?)-dot-([\w-]+?)-dot-(\w+)$'
  84. '$1.$2.$3';
  85. '~^([\w-]+?)-dot-(\w+)$'
  86. '$1.$2';
  87. }
  88. map $_vhost $_vhost_dec_ext {
  89. volatile; #.example.com
  90. '~^(?<_ext_src>[^.]+)\.ext\.[\w-]+\.\w+$' $_ext_dst;
  91. }
  92. # 虚拟域名 -> 真实域名
  93. map $_vhost $_vhost_to_rhost {
  94. volatile;
  95. hostnames;
  96. include include/vhost-rhost.map;
  97. }
  98. # 真实域名 -> 虚拟域名
  99. map $_rhost $_rhost_to_vhost {
  100. volatile;
  101. hostnames;
  102. include include/rhost-vhost.map;
  103. }
  104. # TODO: 由于 hostnames 无法获取 * 部分,暂时先这样获取子域
  105. # *.com -> *
  106. map $_rhost $_rhost_slice_0 {
  107. volatile;
  108. '~^(.+?)\.\w+$' $1;
  109. }
  110. # *.google.com -> *
  111. map $_rhost $_rhost_slice_1 {
  112. volatile;
  113. '~^(.+?)\.(?:[\w-]+\.){1}\w+$' $1;
  114. }
  115. # *.google.com.hk -> *
  116. map $_rhost $_rhost_slice_2 {
  117. volatile;
  118. '~^(.+?)\.(?:[\w-]+\.){2}\w+$' $1;
  119. }
  120. # *.wk -> *
  121. map $_vhost $_vhost_slice_0 {
  122. volatile; #.example.com
  123. '~^(.+?)\.\w+\.[\w-]+\.\w+$' $1;
  124. }
  125. # *.m.wk -> *
  126. map $_vhost $_vhost_slice_1 {
  127. volatile; #.example.com
  128. '~^(.+?)\.(?:[\w-]+\.){1}\w+\.[\w-]+\.\w+$' $1;
  129. }
  130. ##########
  131. # 静态资源站点
  132. server {
  133. include include/host-root.conf;
  134. root ../www;
  135. charset utf-8;
  136. add_header cache-control max-age=300;
  137. add_header strict-transport-security 'max-age=99999999; includeSubDomains; preload';
  138. # 需要编译 ngx_brotli 模块(参考 setup.sh)
  139. brotli_static on;
  140. }
  141. # 内置站点代理
  142. # 格式为 https://[sub.]alias.example.com/path/to/?query
  143. server {
  144. include include/host-wild.conf;
  145. location / {
  146. set $_vhost $host;
  147. set $_site $_vhost_to_rhost;
  148. if ($_site = '') {
  149. return 404 "unknown site";
  150. }
  151. include proc-hdr.conf;
  152. # 非 JS 发送的请求,返回安装 ServiceWorker 的页面
  153. # 该请求为首次访问时发起,后续请求会被 SW 拦截并带上 JS 标记
  154. if ($_hasSw = '0') {
  155. rewrite ^ /__setup.html;
  156. }
  157. set $_proto 'https';
  158. if ($_isHttp = '1') {
  159. set $_proto 'http';
  160. }
  161. if ($_port) {
  162. set $_port ':$_port';
  163. }
  164. # CORS preflight
  165. if ($request_method = 'OPTIONS') {
  166. more_set_headers
  167. 'access-control-allow-origin: $_acao'
  168. 'access-control-allow-Methods: GET, POST, PUT, DELETE, HEAD, OPTIONS'
  169. 'access-control-allow-Headers: $http_Access_Control_Request_Headers'
  170. 'access-control-max-Age: 1728000'
  171. ;
  172. return 204;
  173. }
  174. # return 200 "[debug]
  175. # request_uri: $request_uri
  176. # host: $host
  177. # isHttp: $_isHttp
  178. # uri: $uri
  179. # args: $args
  180. # is_args: $is_args
  181. # _ref: $_ref
  182. # _ori: $_ori
  183. # _hasSw: $_hasSw
  184. # proxy: $_proto://$_site$_port;
  185. # ";
  186. access_log logs/proxy.log log_proxy buffer=64k flush=1s;
  187. proxy_pass $_proto://$_site$_port;
  188. # 将返回头 set-cookie 中的 domain 部分转换成我们的虚拟域名
  189. proxy_cookie_domain ~^\.?(?<_rhost>.*)$ $_rhost_to_vhost;
  190. }
  191. location = /__setup.html {
  192. internal;
  193. brotli_static on;
  194. charset utf-8;
  195. root ../www;
  196. etag off;
  197. more_clear_headers Accept-Ranges Last-Modified;
  198. }
  199. # 由于 ServiceWorker 脚本必须位于同源站点,
  200. # 因此为了减少重复加载,此处只返回实际脚本的引用。
  201. location = /__sw.js {
  202. add_header cache-control max-age=9999999;
  203. include include/x-js.conf;
  204. }
  205. }
  206. # 测试案例(暂未完成)
  207. #include test.conf;
  208. }