openvibers/openvibe.mediahub Commits
MediaHub vhost: form writes only on the strict zone (GET /files is a page), /internal/ 404, security.txt, and openvibe.pics / openvibe.video server blocks with their own certificates
Changes
@@@ -12,6 +12,14 @@limit_req_zone $binary_remote_addr zone=media-hub_auth:10m rate=10r/m;limit_req_zone $binary_remote_addr zone=media-hub_api:10m rate=5r/s;limit_req_zone $binary_remote_addr zone=media-hub_forms:10m rate=1r/s;++# Form writes only: reading /files is a page like any other (an empty key is not counted; limit_req is not allowed++# inside limit_except).++map $request_method $media_hub_write_key {++ GET "";++ HEAD "";++ default $binary_remote_addr;++}++limit_req_zone $media_hub_write_key zone=media-hub_writes:10m rate=1r/s;server {listen 80;@@@ -41,6 +49,7 @@ server {http2 on;server_name openvibe.download;++ include snippets/security-txt.conf; # /.well-known/security.txt (host file; SECURITY.md in every repo)ssl_certificate /etc/letsencrypt/live/openvibe.download/fullchain.pem;ssl_certificate_key /etc/letsencrypt/live/openvibe.download/privkey.pem;ssl_protocols TLSv1.2 TLSv1.3;@@@ -125,12 +134,13 @@ server {# ── Form writes (the upload form is the exact match above) ──location ~ ^/(files|folders|shares|staff)(/|$) {-- limit_req zone=media-hub_forms burst=10 nodelay;++ limit_req zone=media-hub_writes burst=10 nodelay;limit_req_status 429;proxy_pass http://127.0.0.1:4990;}-- # ── Prometheus metrics: host-local scrapers only (http://127.0.0.1:4990/metrics) ──++ # ── Loopback only: OpenVibe.Events' deliveries (account export and deletion) and Prometheus ──++ location /internal/ { return 404; }location = /metrics { return 404; }# ── Pages, docs, robots.txt, sitemap, static assets ─────@@@ -142,3 +152,99 @@ server {deny all;}}++++# ── openvibe.pics and openvibe.video: the same process answers by Host with "coming" pages (no uploads there) ──++server {++ listen 80;++ listen [::]:80;++ server_name openvibe.pics www.openvibe.pics openvibe.video www.openvibe.video;++++ location /.well-known/acme-challenge/ { root /var/www/certbot; }++ location / { return 301 https://$host$request_uri; }++}++++server {++ listen 443 ssl;++ listen [::]:443 ssl;++ http2 on;++ server_name www.openvibe.pics;++ ssl_certificate /etc/letsencrypt/live/openvibe.pics/fullchain.pem;++ ssl_certificate_key /etc/letsencrypt/live/openvibe.pics/privkey.pem;++ return 301 https://openvibe.pics$request_uri;++}++++server {++ listen 443 ssl;++ listen [::]:443 ssl;++ http2 on;++ server_name www.openvibe.video;++ ssl_certificate /etc/letsencrypt/live/openvibe.video/fullchain.pem;++ ssl_certificate_key /etc/letsencrypt/live/openvibe.video/privkey.pem;++ return 301 https://openvibe.video$request_uri;++}++++server {++ listen 443 ssl;++ listen [::]:443 ssl;++ http2 on;++ server_name openvibe.pics;++ include snippets/security-txt.conf;++ ssl_certificate /etc/letsencrypt/live/openvibe.pics/fullchain.pem;++ ssl_certificate_key /etc/letsencrypt/live/openvibe.pics/privkey.pem;++ ssl_protocols TLSv1.2 TLSv1.3;++ access_log /var/log/nginx/openvibe.pics.access.log;++ error_log /var/log/nginx/openvibe.pics.error.log;++ client_max_body_size 128k;++ add_header X-Content-Type-Options nosniff always;++ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;++ gzip on;++ gzip_types text/css application/javascript application/json text/plain application/xml;++ proxy_http_version 1.1;++ proxy_set_header Host $host;++ proxy_set_header X-Real-IP $remote_addr;++ proxy_set_header X-Forwarded-For $remote_addr;++ proxy_set_header CF-Connecting-IP $remote_addr;++ proxy_set_header X-Forwarded-Proto $scheme;++ location /auth/ {++ limit_req zone=media-hub_auth burst=10 nodelay;++ limit_req_status 429;++ proxy_pass http://127.0.0.1:4990;++ }++ location /internal/ { return 404; }++ location = /metrics { return 404; }++ location / { proxy_pass http://127.0.0.1:4990; }++ location ~ /\.(?!well-known) { deny all; }++}++++server {++ listen 443 ssl;++ listen [::]:443 ssl;++ http2 on;++ server_name openvibe.video;++ include snippets/security-txt.conf;++ ssl_certificate /etc/letsencrypt/live/openvibe.video/fullchain.pem;++ ssl_certificate_key /etc/letsencrypt/live/openvibe.video/privkey.pem;++ ssl_protocols TLSv1.2 TLSv1.3;++ access_log /var/log/nginx/openvibe.video.access.log;++ error_log /var/log/nginx/openvibe.video.error.log;++ client_max_body_size 128k;++ add_header X-Content-Type-Options nosniff always;++ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;++ gzip on;++ gzip_types text/css application/javascript application/json text/plain application/xml;++ proxy_http_version 1.1;++ proxy_set_header Host $host;++ proxy_set_header X-Real-IP $remote_addr;++ proxy_set_header X-Forwarded-For $remote_addr;++ proxy_set_header CF-Connecting-IP $remote_addr;++ proxy_set_header X-Forwarded-Proto $scheme;++ location /auth/ {++ limit_req zone=media-hub_auth burst=10 nodelay;++ limit_req_status 429;++ proxy_pass http://127.0.0.1:4990;++ }++ location /internal/ { return 404; }++ location = /metrics { return 404; }++ location / { proxy_pass http://127.0.0.1:4990; }++ location ~ /\.(?!well-known) { deny all; }++}
@@ -12,6 +12,14 @@
@@ -12,6 +12,14 @@
limit_req_zone $binary_remote_addr zone=media-hub_auth:10m rate=10r/m;
limit_req_zone $binary_remote_addr zone=media-hub_auth:10m rate=10r/m;
limit_req_zone $binary_remote_addr zone=media-hub_api:10m rate=5r/s;
limit_req_zone $binary_remote_addr zone=media-hub_api:10m rate=5r/s;
limit_req_zone $binary_remote_addr zone=media-hub_forms:10m rate=1r/s;
limit_req_zone $binary_remote_addr zone=media-hub_forms:10m rate=1r/s;
+# Form writes only: reading /files is a page like any other (an empty key is not counted; limit_req is not allowed
+# inside limit_except).
+map $request_method $media_hub_write_key {
+ GET "";
+ HEAD "";
+ default $binary_remote_addr;
+}
+limit_req_zone $media_hub_write_key zone=media-hub_writes:10m rate=1r/s;
server {
server {
listen 80;
listen 80;
@@ -41,6 +49,7 @@ server {
@@ -41,6 +49,7 @@ server {
http2 on;
http2 on;
server_name openvibe.download;
server_name openvibe.download;
+ include snippets/security-txt.conf; # /.well-known/security.txt (host file; SECURITY.md in every repo)
ssl_certificate /etc/letsencrypt/live/openvibe.download/fullchain.pem;
ssl_certificate /etc/letsencrypt/live/openvibe.download/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/openvibe.download/privkey.pem;
ssl_certificate_key /etc/letsencrypt/live/openvibe.download/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_protocols TLSv1.2 TLSv1.3;
@@ -125,12 +134,13 @@ server {
@@ -125,12 +134,13 @@ server {
# ── Form writes (the upload form is the exact match above) ──
# ── Form writes (the upload form is the exact match above) ──
location ~ ^/(files|folders|shares|staff)(/|$) {
location ~ ^/(files|folders|shares|staff)(/|$) {
- limit_req zone=media-hub_forms burst=10 nodelay;
+ limit_req zone=media-hub_writes burst=10 nodelay;
limit_req_status 429;
limit_req_status 429;
proxy_pass http://127.0.0.1:4990;
proxy_pass http://127.0.0.1:4990;
}
}
- # ── Prometheus metrics: host-local scrapers only (http://127.0.0.1:4990/metrics) ──
+ # ── Loopback only: OpenVibe.Events' deliveries (account export and deletion) and Prometheus ──
+ location /internal/ { return 404; }
location = /metrics { return 404; }
location = /metrics { return 404; }
# ── Pages, docs, robots.txt, sitemap, static assets ─────
# ── Pages, docs, robots.txt, sitemap, static assets ─────
@@ -142,3 +152,99 @@ server {
@@ -142,3 +152,99 @@ server {
deny all;
deny all;
}
}
}
}
+
+# ── openvibe.pics and openvibe.video: the same process answers by Host with "coming" pages (no uploads there) ──
+server {
+ listen 80;
+ listen [::]:80;
+ server_name openvibe.pics www.openvibe.pics openvibe.video www.openvibe.video;
+
+ location /.well-known/acme-challenge/ { root /var/www/certbot; }
+ location / { return 301 https://$host$request_uri; }
+}
+
+server {
+ listen 443 ssl;
+ listen [::]:443 ssl;
+ http2 on;
+ server_name www.openvibe.pics;
+ ssl_certificate /etc/letsencrypt/live/openvibe.pics/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/openvibe.pics/privkey.pem;
+ return 301 https://openvibe.pics$request_uri;
+}
+
+server {
+ listen 443 ssl;
+ listen [::]:443 ssl;
+ http2 on;
+ server_name www.openvibe.video;
+ ssl_certificate /etc/letsencrypt/live/openvibe.video/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/openvibe.video/privkey.pem;
+ return 301 https://openvibe.video$request_uri;
+}
+
+server {
+ listen 443 ssl;
+ listen [::]:443 ssl;
+ http2 on;
+ server_name openvibe.pics;
+ include snippets/security-txt.conf;
+ ssl_certificate /etc/letsencrypt/live/openvibe.pics/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/openvibe.pics/privkey.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ access_log /var/log/nginx/openvibe.pics.access.log;
+ error_log /var/log/nginx/openvibe.pics.error.log;
+ client_max_body_size 128k;
+ add_header X-Content-Type-Options nosniff always;
+ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
+ gzip on;
+ gzip_types text/css application/javascript application/json text/plain application/xml;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header CF-Connecting-IP $remote_addr;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ location /auth/ {
+ limit_req zone=media-hub_auth burst=10 nodelay;
+ limit_req_status 429;
+ proxy_pass http://127.0.0.1:4990;
+ }
+ location /internal/ { return 404; }
+ location = /metrics { return 404; }
+ location / { proxy_pass http://127.0.0.1:4990; }
+ location ~ /\.(?!well-known) { deny all; }
+}
+
+server {
+ listen 443 ssl;
+ listen [::]:443 ssl;
+ http2 on;
+ server_name openvibe.video;
+ include snippets/security-txt.conf;
+ ssl_certificate /etc/letsencrypt/live/openvibe.video/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/openvibe.video/privkey.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ access_log /var/log/nginx/openvibe.video.access.log;
+ error_log /var/log/nginx/openvibe.video.error.log;
+ client_max_body_size 128k;
+ add_header X-Content-Type-Options nosniff always;
+ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
+ gzip on;
+ gzip_types text/css application/javascript application/json text/plain application/xml;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header CF-Connecting-IP $remote_addr;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ location /auth/ {
+ limit_req zone=media-hub_auth burst=10 nodelay;
+ limit_req_status 429;
+ proxy_pass http://127.0.0.1:4990;
+ }
+ location /internal/ { return 404; }
+ location = /metrics { return 404; }
+ location / { proxy_pass http://127.0.0.1:4990; }
+ location ~ /\.(?!well-known) { deny all; }
+}