gabriel / musehub public
nginx-cf.conf
131 lines 5.1 KB
Raw
sha256:a10adeeb7a0169cb9900f9806ed7a973047258abb6283724fe55e8eb68ff3f0a init: musehub initial commit Human 171 days ago
1 # /etc/nginx/sites-available/musehub
2 #
3 # Cloudflare Origin Certificate configuration.
4 # Cloudflare terminates SSL at the edge. This nginx instance accepts HTTPS
5 # connections using a Cloudflare Origin Certificate.
6 #
7 # SSL mode in Cloudflare dashboard MUST be set to "Full (Strict)".
8 # No Certbot or Let's Encrypt required — the Origin Certificate is valid for 15 years.
9 #
10 # IP restriction is enforced at the EC2 security group level (inbound port 443
11 # restricted to Cloudflare IP ranges). Do not duplicate that logic here —
12 # the real_ip module replaces $remote_addr with the true client IP before
13 # allow/deny runs, which would incorrectly block legitimate Cloudflare traffic.
14 #
15 # To generate the Origin Certificate:
16 # Cloudflare Dashboard → <domain> → SSL/TLS → Origin Server → Create Certificate
17 # Choose "Generate private key and CSR with Cloudflare" → RSA (2048) → 15 years
18 # Save certificate → /etc/ssl/cloudflare/origin.pem
19 # Save private key → /etc/ssl/cloudflare/origin.key
20 # chmod 640 /etc/ssl/cloudflare/origin.key
21
22 # Restore the real client IP from the Cloudflare connecting-IP header.
23 # Without this, every request appears to come from a Cloudflare edge node.
24 # Cloudflare IP ranges: https://www.cloudflare.com/ips/
25 real_ip_header CF-Connecting-IP;
26 real_ip_recursive on;
27
28 # Cloudflare IPv4 ranges
29 set_real_ip_from 173.245.48.0/20;
30 set_real_ip_from 103.21.244.0/22;
31 set_real_ip_from 103.22.200.0/22;
32 set_real_ip_from 103.31.4.0/22;
33 set_real_ip_from 141.101.64.0/18;
34 set_real_ip_from 108.162.192.0/18;
35 set_real_ip_from 190.93.240.0/20;
36 set_real_ip_from 188.114.96.0/20;
37 set_real_ip_from 197.234.240.0/22;
38 set_real_ip_from 198.41.128.0/17;
39 set_real_ip_from 162.158.0.0/15;
40 set_real_ip_from 104.16.0.0/13;
41 set_real_ip_from 104.24.0.0/14;
42 set_real_ip_from 172.64.0.0/13;
43 set_real_ip_from 131.0.72.0/22;
44
45 # Cloudflare IPv6 ranges
46 set_real_ip_from 2400:cb00::/32;
47 set_real_ip_from 2606:4700::/32;
48 set_real_ip_from 2803:f800::/32;
49 set_real_ip_from 2405:b500::/32;
50 set_real_ip_from 2405:8100::/32;
51 set_real_ip_from 2a06:98c0::/29;
52 set_real_ip_from 2c0f:f248::/32;
53
54 # Blue-green upstream: deploy.sh rewrites /etc/nginx/musehub-active-port
55 # and runs `nginx -s reload` to switch slots atomically.
56 upstream musehub_backend {
57 include /etc/nginx/musehub-active-port;
58 }
59
60 # Redirect all plain-HTTP traffic to HTTPS — 301 (permanent, cacheable).
61 # In prod, Cloudflare enforces HTTPS at the edge, so this only fires for
62 # traffic that bypasses Cloudflare (e.g., direct-to-origin access during
63 # ops or monitoring). Belt-and-suspenders.
64 server {
65 listen 80;
66 listen [::]:80;
67 server_name DOMAIN_PLACEHOLDER;
68 return 301 https://$host$request_uri;
69 }
70
71 # ── Gzip compression ─────────────────────────────────────────────────────────
72 # Cloudflare compresses at the edge, but gzip here covers direct-to-origin
73 # access (monitoring, ops, Cloudflare cache miss fills).
74 gzip on;
75 gzip_comp_level 6;
76 gzip_min_length 1024;
77 gzip_vary on;
78 gzip_proxied any;
79 gzip_types
80 text/css
81 text/javascript
82 application/javascript
83 application/json
84 text/plain
85 text/html
86 image/svg+xml
87 application/xml;
88
89 server {
90 listen 443 ssl;
91 listen [::]:443 ssl;
92 server_name DOMAIN_PLACEHOLDER;
93
94 ssl_certificate /etc/ssl/cloudflare/origin.pem;
95 ssl_certificate_key /etc/ssl/cloudflare/origin.key;
96
97 # Enforce TLS 1.2 minimum — disable TLS 1.0 and TLS 1.1 (both deprecated).
98 # TLS 1.3 is preferred; 1.2 retained for compatibility with older clients.
99 ssl_protocols TLSv1.2 TLSv1.3;
100 ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256;
101 ssl_prefer_server_ciphers off; # TLS 1.3 ignores this; keep off for 1.2 forward secrecy
102
103 client_max_body_size 500m;
104
105 # Push endpoints need a longer timeout — large repos can take several seconds
106 # to serialize and write all objects.
107 # /push/objects is Phase 1 (object pre-upload).
108 # /push is Phase 2 (commits + snapshots, refs updated atomically).
109 location ~ ^/[^/]+/[^/]+/push(/objects)?$ {
110 proxy_pass http://musehub_backend;
111 proxy_http_version 1.1;
112 proxy_set_header Host $host;
113 proxy_set_header X-Real-IP $remote_addr;
114 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
115 proxy_set_header X-Forwarded-Proto $scheme;
116 proxy_read_timeout 300s;
117 }
118
119 # Proxy all other traffic to the MuseHub uvicorn container
120 location / {
121 proxy_pass http://musehub_backend;
122 proxy_http_version 1.1;
123 proxy_set_header Upgrade $http_upgrade;
124 proxy_set_header Connection "upgrade";
125 proxy_set_header Host $host;
126 proxy_set_header X-Real-IP $remote_addr;
127 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
128 proxy_set_header X-Forwarded-Proto $scheme;
129 proxy_read_timeout 60s;
130 }
131 }
File History 1 commit
sha256:a10adeeb7a0169cb9900f9806ed7a973047258abb6283724fe55e8eb68ff3f0a init: musehub initial commit Human 171 days ago