openvibers/openvibe.games Commits
nginx: the repo vhost is production's again (www redirect, security.txt, /tos) plus /internal/ and /metrics closed at the edge and HSTS, nosniff and a referrer policy (#98)
Changes
@@@ -14,27 +14,36 @@ map $http_upgrade $connection_upgrade {server {listen 80;listen [::]:80;-- server_name openvibe.games play.openvibe.games;++ server_name openvibe.games www.openvibe.games play.openvibe.games;++ return 301 https://$host$request_uri;++}-- location /.well-known/acme-challenge/ { root /var/www/certbot; }-- location / { return 301 https://$host$request_uri; }++# www → apex (the wildcard certificate covers www).++server {++ listen 443 ssl http2;++ listen [::]:443 ssl http2;++ server_name www.openvibe.games;++ ssl_certificate /etc/letsencrypt/live/openvibe.games/fullchain.pem;++ ssl_certificate_key /etc/letsencrypt/live/openvibe.games/privkey.pem;++ return 301 https://openvibe.games$request_uri;}server {listen 443 ssl http2;listen [::]:443 ssl http2;server_name openvibe.games;++ include snippets/security-txt.conf;ssl_certificate /etc/letsencrypt/live/openvibe.games/fullchain.pem;ssl_certificate_key /etc/letsencrypt/live/openvibe.games/privkey.pem;client_max_body_size 64m; # map saves + editor asset uploads (48 MB cap in-app)-- # Readiness is for callers on the host (curl 127.0.0.1:8000/api/ready),-- # not the internet: everything else under /api/ is proxied as-is below.-- location = /api/ready {-- return 404;-- }++ # Terms, Privacy and DMCA: static pages built by OpenVibe.Sites (openvibe-shared/legal).++ location = /tos { return 301 /terms; }++++ # Readiness is for callers on the host (curl 127.0.0.1:8000/api/ready), not the internet.++ location = /api/ready { return 404; }# ── The Events webhook: OpenVibe.Events delivers over loopback, never through the public vhosts ──location /internal/ { return 404; }@@@ -42,6 +51,12 @@ server {# ── Prometheus metrics: host-local scrapers only (http://127.0.0.1:8000/metrics) ──location = /metrics { return 404; }++ # The game server sends no security headers of its own (2026-10-17: none at all on openvibe.games). No CSP or++ # frame rule here: games and worlds are embedded elsewhere and load from several origins.++ add_header Strict-Transport-Security "max-age=31536000" always;++ add_header X-Content-Type-Options "nosniff" always;++ add_header Referrer-Policy "strict-origin-when-cross-origin" always;++location / {proxy_pass http://127.0.0.1:8000;proxy_http_version 1.1;@@@ -63,15 +78,15 @@ server {listen 443 ssl http2;listen [::]:443 ssl http2;server_name play.openvibe.games;++ include snippets/security-txt.conf;ssl_certificate /etc/letsencrypt/live/openvibe.games/fullchain.pem;ssl_certificate_key /etc/letsencrypt/live/openvibe.games/privkey.pem;client_max_body_size 64m;-- location = /api/ready {-- return 404;-- }++ # Readiness is for callers on the host (curl 127.0.0.1:8000/api/ready), not the internet.++ location = /api/ready { return 404; }# ── The Events webhook: OpenVibe.Events delivers over loopback, never through the public vhosts ──location /internal/ { return 404; }@@@ -79,6 +94,12 @@ server {# ── Prometheus metrics: host-local scrapers only (http://127.0.0.1:8000/metrics) ──location = /metrics { return 404; }++ # The game server sends no security headers of its own (2026-10-17: none at all on openvibe.games). No CSP or++ # frame rule here: games and worlds are embedded elsewhere and load from several origins.++ add_header Strict-Transport-Security "max-age=31536000" always;++ add_header X-Content-Type-Options "nosniff" always;++ add_header Referrer-Policy "strict-origin-when-cross-origin" always;++location / {proxy_pass http://127.0.0.1:8000;proxy_http_version 1.1;
@@ -14,27 +14,36 @@ map $http_upgrade $connection_upgrade {
@@ -14,27 +14,36 @@ map $http_upgrade $connection_upgrade {
server {
server {
listen 80;
listen 80;
listen [::]:80;
listen [::]:80;
- server_name openvibe.games play.openvibe.games;
+ server_name openvibe.games www.openvibe.games play.openvibe.games;
+ return 301 https://$host$request_uri;
+}
- location /.well-known/acme-challenge/ { root /var/www/certbot; }
- location / { return 301 https://$host$request_uri; }
+# www → apex (the wildcard certificate covers www).
+server {
+ listen 443 ssl http2;
+ listen [::]:443 ssl http2;
+ server_name www.openvibe.games;
+ ssl_certificate /etc/letsencrypt/live/openvibe.games/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/openvibe.games/privkey.pem;
+ return 301 https://openvibe.games$request_uri;
}
}
server {
server {
listen 443 ssl http2;
listen 443 ssl http2;
listen [::]:443 ssl http2;
listen [::]:443 ssl http2;
server_name openvibe.games;
server_name openvibe.games;
+ include snippets/security-txt.conf;
ssl_certificate /etc/letsencrypt/live/openvibe.games/fullchain.pem;
ssl_certificate /etc/letsencrypt/live/openvibe.games/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/openvibe.games/privkey.pem;
ssl_certificate_key /etc/letsencrypt/live/openvibe.games/privkey.pem;
client_max_body_size 64m; # map saves + editor asset uploads (48 MB cap in-app)
client_max_body_size 64m; # map saves + editor asset uploads (48 MB cap in-app)
- # Readiness is for callers on the host (curl 127.0.0.1:8000/api/ready),
- # not the internet: everything else under /api/ is proxied as-is below.
- location = /api/ready {
- return 404;
- }
+ # Terms, Privacy and DMCA: static pages built by OpenVibe.Sites (openvibe-shared/legal).
+ location = /tos { return 301 /terms; }
+
+ # Readiness is for callers on the host (curl 127.0.0.1:8000/api/ready), not the internet.
+ location = /api/ready { return 404; }
# ── The Events webhook: OpenVibe.Events delivers over loopback, never through the public vhosts ──
# ── The Events webhook: OpenVibe.Events delivers over loopback, never through the public vhosts ──
location /internal/ { return 404; }
location /internal/ { return 404; }
@@ -42,6 +51,12 @@ server {
@@ -42,6 +51,12 @@ server {
# ── Prometheus metrics: host-local scrapers only (http://127.0.0.1:8000/metrics) ──
# ── Prometheus metrics: host-local scrapers only (http://127.0.0.1:8000/metrics) ──
location = /metrics { return 404; }
location = /metrics { return 404; }
+ # The game server sends no security headers of its own (2026-10-17: none at all on openvibe.games). No CSP or
+ # frame rule here: games and worlds are embedded elsewhere and load from several origins.
+ add_header Strict-Transport-Security "max-age=31536000" always;
+ add_header X-Content-Type-Options "nosniff" always;
+ add_header Referrer-Policy "strict-origin-when-cross-origin" always;
+
location / {
location / {
proxy_pass http://127.0.0.1:8000;
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_http_version 1.1;
@@ -63,15 +78,15 @@ server {
@@ -63,15 +78,15 @@ server {
listen 443 ssl http2;
listen 443 ssl http2;
listen [::]:443 ssl http2;
listen [::]:443 ssl http2;
server_name play.openvibe.games;
server_name play.openvibe.games;
+ include snippets/security-txt.conf;
ssl_certificate /etc/letsencrypt/live/openvibe.games/fullchain.pem;
ssl_certificate /etc/letsencrypt/live/openvibe.games/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/openvibe.games/privkey.pem;
ssl_certificate_key /etc/letsencrypt/live/openvibe.games/privkey.pem;
client_max_body_size 64m;
client_max_body_size 64m;
- location = /api/ready {
- return 404;
- }
+ # Readiness is for callers on the host (curl 127.0.0.1:8000/api/ready), not the internet.
+ location = /api/ready { return 404; }
# ── The Events webhook: OpenVibe.Events delivers over loopback, never through the public vhosts ──
# ── The Events webhook: OpenVibe.Events delivers over loopback, never through the public vhosts ──
location /internal/ { return 404; }
location /internal/ { return 404; }
@@ -79,6 +94,12 @@ server {
@@ -79,6 +94,12 @@ server {
# ── Prometheus metrics: host-local scrapers only (http://127.0.0.1:8000/metrics) ──
# ── Prometheus metrics: host-local scrapers only (http://127.0.0.1:8000/metrics) ──
location = /metrics { return 404; }
location = /metrics { return 404; }
+ # The game server sends no security headers of its own (2026-10-17: none at all on openvibe.games). No CSP or
+ # frame rule here: games and worlds are embedded elsewhere and load from several origins.
+ add_header Strict-Transport-Security "max-age=31536000" always;
+ add_header X-Content-Type-Options "nosniff" always;
+ add_header Referrer-Policy "strict-origin-when-cross-origin" always;
+
location / {
location / {
proxy_pass http://127.0.0.1:8000;
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_http_version 1.1;