# ───────────────────────────────────────────────────────────────────────────── # DorkNet — nginx config for the Rec Room private server (March 2020 build) # ───────────────────────────────────────────────────────────────────────────── # # What this does: # • Listens on :80 (HTTP) and :443 (HTTPS) for every *.rec.net subdomain # • Terminates TLS using a single mkcert wildcard cert # • Proxies all HTTP traffic to the DorkNet.Server backend on 127.0.0.1:5137 # • Forwards the Host header so ASP.NET Core's [Host("subdomain.rec.net")] # attribute routing keeps working # • Supports WebSocket upgrades — required for: # - notify.rec.net/hub/v1 (SignalR Core; client uses BestHTTP.SignalRCore) # - notify.rec.net/notify/v1 (legacy custom WebSocket) # • Long read timeouts (1h) so SignalR/WS connections don't get axed mid-session # • No request-body size limit so multipart form uploads work # # Two preconditions before this is useful: # 1) mkcert ran: mkcert -install && mkcert "*.rec.net" rec.net # → produces _wildcard.rec.net.pem and _wildcard.rec.net-key.pem # → fix the absolute paths in the ssl_certificate lines below # 2) hosts file maps every *.rec.net subdomain to 127.0.0.1 # (a sample block is at the bottom of this file) # # Where to put this file: # • Windows: C:\nginx\conf\nginx.conf (replace the default) # • Linux: /etc/nginx/sites-available/dorknet # then symlink to /etc/nginx/sites-enabled/ # • Validate: nginx -t # • Reload: nginx -s reload (or systemctl reload nginx) # # If you change the .NET dev port (DorkNet.Server/Properties/launchSettings.json # applicationUrl), update the `set $backend` line below to match. # ───────────────────────────────────────────────────────────────────────────── worker_processes auto; events { worker_connections 4096; } http { # ── MIME / logging ─────────────────────────────────────────────────────── include mime.types; default_type application/octet-stream; log_format dorknet '$remote_addr - $host "$request" ' '$status $body_bytes_sent ${request_time}s ' '"$http_user_agent"'; access_log logs/access.log dorknet; error_log logs/error.log warn; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65s; server_tokens off; # ── Body size — multipart uploads on bulk endpoints, image uploads ────── # Set to 0 for unlimited, or pick a sane cap. 32MB covers profile images. client_max_body_size 32m; # ── Buffers — large enough for the kitchen-sink config response ────────── # /api/config/v2 can be 5–10KB; default 4k buffers cause "upstream sent too # big header" 502s. proxy_buffer_size 16k; proxy_buffers 8 32k; proxy_busy_buffers_size 64k; # ── Connection-Upgrade map — required for any WebSocket route ──────────── # When the client sends `Upgrade: websocket`, this map produces # `Connection: upgrade`. For non-WS traffic it produces "" (empty), which # is what plain HTTP requires. map $http_upgrade $connection_upgrade { default upgrade; '' ''; } # ── HTTP → HTTPS redirect (port 80 → 443) ──────────────────────────────── server { listen 80; listen [::]:80; server_name *.rec.net rec.net; # ACME / health-check passthroughs would go here. Otherwise everything # gets bumped to HTTPS. location / { return 301 https://$host$request_uri; } } # ── Main TLS server — every *.rec.net subdomain ────────────────────────── server { listen 443 ssl; listen [::]:443 ssl; http2 on; # Match every Rec Room subdomain (api, accounts, auth, match, rooms, …) # plus the bare apex domain. The Host header gets forwarded intact, so # ASP.NET Core's [Host(...)] attribute routing dispatches per-subdomain. server_name *.rec.net rec.net; # ─── TLS — mkcert wildcard cert ───────────────────────────────────── # CHANGE THESE TWO PATHS to wherever mkcert dropped the files. # Quickly find them: mkcert -CAROOT # And the cert PEM is wherever you ran `mkcert "*.rec.net" rec.net`. ssl_certificate C:/Users/you/Documents/DorkNet/_wildcard.rec.net.pem; ssl_certificate_key C:/Users/you/Documents/DorkNet/_wildcard.rec.net-key.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # ─── Backend ──────────────────────────────────────────────────────── # The DorkNet.Server Kestrel listener. Change the port here if you # change Properties/launchSettings.json applicationUrl. set $backend http://127.0.0.1:5137; # ─── Catch-all proxy: every path goes to DorkNet.Server ────────────── location / { proxy_pass $backend; # Preserve the original Host so ASP.NET Core's [Host("api.rec.net")] # routing dispatches by subdomain. 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; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; # WebSocket upgrade — required for SignalR (notify.rec.net/hub/v1) # and the custom WS at notify.rec.net/notify/v1. The # $connection_upgrade var is the map() above. proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; # Long timeouts so WebSocket / SSE connections survive idle. # 1 hour is plenty for a play session; bump if you see disconnects. proxy_connect_timeout 60s; proxy_send_timeout 3600s; proxy_read_timeout 3600s; # Don't buffer streaming responses — the SignalR transport breaks # if frames are buffered before being flushed to the client. proxy_buffering off; proxy_request_buffering off; # Faster failure when the backend is actually down — avoids the # 30-second hangs that otherwise pile up under retry storms. proxy_next_upstream error timeout invalid_header http_502 http_503; proxy_next_upstream_tries 1; } # ─── Optional: explicit WS routes for clarity (not strictly required; # the location / above already handles them via the upgrade map). ──── # location /hub/v1 { proxy_pass $backend; ... } # location /notify/v1 { proxy_pass $backend; ... } } } # ───────────────────────────────────────────────────────────────────────────── # hosts file companion entries # Add to: # • Windows: C:\Windows\System32\drivers\etc\hosts (Notepad as Admin) # • Linux/Mac: /etc/hosts # # Replace 127.0.0.1 with your server's LAN IP if other machines connect to it. # ───────────────────────────────────────────────────────────────────────────── # # 127.0.0.1 rec.net # 127.0.0.1 api.rec.net # 127.0.0.1 accounts.rec.net # 127.0.0.1 auth.rec.net # 127.0.0.1 bugreporting.rec.net # 127.0.0.1 cards.rec.net # 127.0.0.1 cdn.rec.net # 127.0.0.1 chat.rec.net # 127.0.0.1 clubs.rec.net # 127.0.0.1 cms.rec.net # 127.0.0.1 commerce.rec.net # 127.0.0.1 data.rec.net # 127.0.0.1 datacollection.rec.net # 127.0.0.1 discovery.rec.net # 127.0.0.1 econ.rec.net # 127.0.0.1 gamelogs.rec.net # 127.0.0.1 geo.rec.net # 127.0.0.1 img.rec.net # 127.0.0.1 leaderboard.rec.net # 127.0.0.1 link.rec.net # 127.0.0.1 lists.rec.net # 127.0.0.1 match.rec.net # 127.0.0.1 moderation.rec.net # 127.0.0.1 ns.rec.net # 127.0.0.1 notify.rec.net # 127.0.0.1 platformnotifications.rec.net # 127.0.0.1 playersettings.rec.net # 127.0.0.1 roomcomments.rec.net # 127.0.0.1 roomieintegrations.rec.net # 127.0.0.1 rooms.rec.net # 127.0.0.1 storage.rec.net # 127.0.0.1 strings.rec.net # 127.0.0.1 strings-cdn.rec.net # 127.0.0.1 studio.rec.net # 127.0.0.1 thorn.rec.net # 127.0.0.1 videos.rec.net