You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
3.9 KiB

  1. upstream app_server {
  2. server unix:/run/gunicorn/socket fail_timeout=0;
  3. }
  4. # define map to set Expires+Cache-Control headers for files based on type
  5. map $sent_http_content_type $expires_type_map {
  6. default off;
  7. text/css max;
  8. application/javascript max;
  9. image/x-icon 1d;
  10. ~image/ max;
  11. }
  12. map $request_uri $csp_header {
  13. # The default CSP:
  14. # - "img-src data:" is needed for Spectre.css icons
  15. default "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src 'self'; manifest-src 'self'; form-action 'self'; frame-ancestors 'none'; base-uri 'none'";
  16. # The CSP for the Stripe donation page:
  17. # - "https://js.stripe.com" in script-src and frame-src is needed for Stripe
  18. "~^/donate_stripe$" "default-src 'none'; script-src 'self' https://js.stripe.com; style-src 'self'; img-src 'self' data:; connect-src 'self'; manifest-src 'self'; frame-src 'self' https://js.stripe.com; form-action 'self'; frame-ancestors 'none'; base-uri 'none'";
  19. }
  20. server {
  21. # block bots that don't obey robots.txt
  22. if ($http_user_agent ~* (SemrushBot)) {
  23. return 403;
  24. }
  25. # remove trailing slash from addresses, the $port thing is a hack for
  26. # development in Vagrant, so the port forwarding from the host is kept
  27. set $port '';
  28. if ($http_host ~ :(\d+)$) {
  29. set $port :$1;
  30. }
  31. rewrite ^/(.*)/$ https://$host$port/$1 permanent;
  32. # redirect /donate to the page on the Docs site
  33. rewrite ^/donate$ https://docs.tildes.net/donate redirect;
  34. # redirect /u/username to /user/username
  35. rewrite ^/u/(.*)$ https://$host$port/user/$1;
  36. listen 443 ssl http2;
  37. listen [::]:443 ssl http2;
  38. {% if nginx_enable_hsts %}
  39. add_header Strict-Transport-Security "max-age={{ hsts_max_age }}; includeSubDomains; preload" always;
  40. {% endif %}
  41. {% if nginx_enable_csp %}
  42. add_header Content-Security-Policy $csp_header always;
  43. {% endif %}
  44. add_header X-Content-Type-Options "nosniff" always;
  45. add_header X-Frame-Options "DENY" always;
  46. add_header X-Xss-Protection "1; mode=block" always;
  47. add_header Referrer-Policy "strict-origin-when-cross-origin" always;
  48. server_name {{ site_hostname }};
  49. keepalive_timeout 5;
  50. root {{ app_dir }}/static;
  51. # Block access to /metrics except from Prometheus server(s)
  52. location /metrics {
  53. {% for ip in prometheus_ips -%}
  54. allow {{ ip }};
  55. {% endfor -%}
  56. deny all;
  57. # try_files is unnecessary here, but I don't know the "proper" way
  58. try_files $uri @proxy_to_app;
  59. }
  60. # add Expires+Cache-Control headers from the mime-type map defined above
  61. expires $expires_type_map;
  62. location / {
  63. # checks for static file, if not found proxy to app
  64. try_files $uri @proxy_to_app;
  65. gzip_static on;
  66. }
  67. location @proxy_to_app {
  68. {% if nginx_enable_ratelimiting %}
  69. # apply rate-limiting, allowing a burst above the limit
  70. limit_req zone=tildes_app burst=5 nodelay;
  71. {% endif -%}
  72. # Cornice adds the X-Content-Type-Options header, so it will end up
  73. # being duplicated since nginx is also configured to send it (above).
  74. # It's better to drop the header coming from Gunicorn here than to
  75. # stop sending it in nginx, since if I ever stop using Cornice I would
  76. # lose that header (and probably not realize).
  77. proxy_hide_header X-Content-Type-Options;
  78. proxy_set_header Host $host;
  79. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  80. proxy_set_header X-Forwarded-Proto $scheme;
  81. proxy_redirect off;
  82. proxy_pass http://app_server;
  83. }
  84. }
  85. {% if nginx_redirect_www %}
  86. # redirect www. to base domain
  87. server {
  88. listen 80;
  89. listen 443 ssl http2;
  90. listen [::]:443 ssl http2;
  91. server_name www.{{ site_hostname }};
  92. return 301 https://{{ site_hostname }}$request_uri;
  93. }
  94. {% endif %}