summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--etc/nginx/sites-available/yummers.dev170
-rwxr-xr-xopt/obsproxy/server.py24
-rwxr-xr-xpush.sh1
4 files changed, 104 insertions, 95 deletions
diff --git a/README.md b/README.md
index 5faee83..9c21585 100644
--- a/README.md
+++ b/README.md
@@ -4,11 +4,11 @@ Shitty service to proxy data from OBS into a low-latency MPEG-DASH stream VRChat
1. Configure OBS with a custom server pointing at `rtmp://<your-domain>/live` and the pre-shared key stored in `STREAM_PSK`.
2. Start the Python service (see `etc/systemd/system/obsproxy.service` for a sample unit).
-3. Share `https://<your-domain>/dash/manifest.mpd` with your VRChat video player. Multiple viewers can consume the feed concurrently.
+3. When the service starts it prints a session-specific manifest URL like `https://<your-domain>/dash/<session-hex>/manifest.mpd`; share that exact URL with your VRChat video player. Multiple viewers can consume the feed concurrently.
Environmental knobs:
- `STREAM_PSK`: required PSK for the single ingest client.
- `DASH_SEGMENT_TIME` / `DASH_FRAGMENT_TIME`: tweak DASH segment/fragment durations to balance latency vs resilience.
-The server seeds a fresh 128-bit session ID on every restart and writes DASH fragments under `<STREAM_DIR>/live/<session-hex>`. The public manifest route stays fixed at `/dash/manifest.mpd`.
+The server seeds a fresh 128-bit session ID on every restart and writes DASH fragments under `<STREAM_DIR>/live/<session-hex>`. The manifest and segments are only exposed under `/dash/<session-hex>/`, making it infeasible to guess a live session path.
diff --git a/etc/nginx/sites-available/yummers.dev b/etc/nginx/sites-available/yummers.dev
index 4f34ff7..0fddcfe 100644
--- a/etc/nginx/sites-available/yummers.dev
+++ b/etc/nginx/sites-available/yummers.dev
@@ -1,95 +1,95 @@
server {
- root /var/www/html;
-
- # Add index.php to the list if you are using PHP
- index index.html index.htm index.nginx-debian.html;
-
- server_name yummers.dev www.yummers.dev;
-
- location / {
- # First attempt to serve request as file, then
- # as directory, then fall back to displaying a 404.
- try_files $uri $uri/ =404;
- }
-
- # Add WebSocket proxy for HR proxy server
- location /hrproxy {
- proxy_pass https://127.0.0.1:2096;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "upgrade";
- 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_read_timeout 300s;
- proxy_send_timeout 300s;
- proxy_buffering off;
- }
-
- # OBS Proxy API endpoints
- location /api/ {
- proxy_pass http://127.0.0.1:5000;
- 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;
- }
-
- # OBS Proxy DASH manifest + segments
- location /dash/ {
- proxy_pass http://127.0.0.1:5000;
- 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;
-
- # Disable buffering/caching so DASH clients see fresh segments immediately
- proxy_buffering off;
- add_header Cache-Control "no-cache" always;
- add_header Access-Control-Allow-Origin "*" always;
-
- proxy_connect_timeout 1h;
- proxy_send_timeout 1h;
- proxy_read_timeout 1h;
- }
-
- # OBS Proxy health check
- location /health {
- proxy_pass http://127.0.0.1:5000/health;
- proxy_set_header Host $host;
- }
-
- # Add RTMP callbacks route
- location /rtmp_callbacks/ {
- proxy_pass http://127.0.0.1:5000;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- }
-
- listen [::]:443 ssl ipv6only=on; # managed by Certbot
- listen 443 ssl; # managed by Certbot
- ssl_certificate /etc/letsencrypt/live/yummers.dev/fullchain.pem; # managed by Certbot
- ssl_certificate_key /etc/letsencrypt/live/yummers.dev/privkey.pem; # managed by Certbot
- include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
- ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
+ root /var/www/html;
+
+ # Add index.php to the list if you are using PHP
+ index index.html index.htm index.nginx-debian.html;
+
+ server_name yummers.dev www.yummers.dev;
+
+ location / {
+ # First attempt to serve request as file, then
+ # as directory, then fall back to displaying a 404.
+ try_files $uri $uri/ =404;
+ }
+
+ # Add WebSocket proxy for HR proxy server
+ location /hrproxy {
+ proxy_pass https://127.0.0.1:2096;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ 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_read_timeout 300s;
+ proxy_send_timeout 300s;
+ proxy_buffering off;
+ }
+
+ # OBS Proxy API endpoints
+ location /api/ {
+ proxy_pass http://127.0.0.1:5000;
+ 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;
+ }
+
+ # OBS Proxy DASH manifest + segments
+ location /dash/ {
+ proxy_pass http://127.0.0.1:5000;
+ 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;
+
+ # Disable buffering/caching so DASH clients see fresh segments immediately
+ proxy_buffering off;
+ add_header Cache-Control "no-cache" always;
+ add_header Access-Control-Allow-Origin "*" always;
+
+ proxy_connect_timeout 1h;
+ proxy_send_timeout 1h;
+ proxy_read_timeout 1h;
+ }
+
+ # OBS Proxy health check
+ location /health {
+ proxy_pass http://127.0.0.1:5000/health;
+ proxy_set_header Host $host;
+ }
+
+ # Add RTMP callbacks route
+ location /rtmp_callbacks/ {
+ proxy_pass http://127.0.0.1:5000;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ }
+
+ listen [::]:443 ssl ipv6only=on; # managed by Certbot
+ listen 443 ssl; # managed by Certbot
+ ssl_certificate /etc/letsencrypt/live/yummers.dev/fullchain.pem; # managed by Certbot
+ ssl_certificate_key /etc/letsencrypt/live/yummers.dev/privkey.pem; # managed by Certbot
+ include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
- if ($host = www.yummers.dev) {
- return 301 https://$host$request_uri;
- } # managed by Certbot
+ if ($host = www.yummers.dev) {
+ return 301 https://$host$request_uri;
+ } # managed by Certbot
- if ($host = yummers.dev) {
- return 301 https://$host$request_uri;
- } # managed by Certbot
+ if ($host = yummers.dev) {
+ return 301 https://$host$request_uri;
+ } # managed by Certbot
- listen 80;
- listen [::]:80;
+ listen 80;
+ listen [::]:80;
- server_name yummers.dev www.yummers.dev;
- return 404; # managed by Certbot
+ server_name yummers.dev www.yummers.dev;
+ return 404; # managed by Certbot
}
diff --git a/opt/obsproxy/server.py b/opt/obsproxy/server.py
index 8191d30..242e223 100755
--- a/opt/obsproxy/server.py
+++ b/opt/obsproxy/server.py
@@ -22,6 +22,7 @@ BASE_DIR = Path(os.environ.get('STREAM_DIR', '/var/www/streams'))
SERVER_DOMAIN = os.environ.get('SERVER_DOMAIN', 'yummers.dev')
STREAM_HEX = secrets.token_hex(16)
STREAM_PATH = BASE_DIR / 'live' / STREAM_HEX
+DASH_ROUTE_PREFIX = f"/dash/{STREAM_HEX}"
# Setup logging
logging.basicConfig(
@@ -74,7 +75,7 @@ def start_ffmpeg_process():
'-map', '0:v:0?',
'-map', '0:a:0?',
'-c:v', 'copy',
- '-c:a', 'aac', '-b:a', '192k',
+ '-c:a', 'copy',
'-f', 'dash',
'-seg_duration', str(DASH_SEGMENT_TIME),
'-frag_duration', str(DASH_FRAGMENT_TIME),
@@ -158,16 +159,20 @@ def cleanup_stream():
# Routes
-@app.route('/dash/manifest.mpd')
+@app.route(f"{DASH_ROUTE_PREFIX}/manifest.mpd")
def serve_dash_manifest():
"""Serve the MPEG-DASH manifest"""
if not stream_active:
return "Stream not found", 404
+ manifest_file = STREAM_PATH / "manifest.mpd"
+ if not manifest_file.exists():
+ return "Manifest not ready", 503
+
return send_from_directory(str(STREAM_PATH), "manifest.mpd")
-@app.route('/dash/<path:filename>')
+@app.route(f"{DASH_ROUTE_PREFIX}/<path:filename>")
def serve_dash_segments(filename):
"""Serve the MPEG-DASH segment files"""
if not stream_active:
@@ -194,8 +199,11 @@ def on_publish():
if not start_ffmpeg_process():
return "Failed to start stream", 500
- logger.info("Stream started successfully")
- logger.info(f"Access stream at https://{SERVER_DOMAIN}/dash/manifest.mpd")
+ logger.info(
+ "Stream active; manifest available at https://%s%s/manifest.mpd",
+ SERVER_DOMAIN,
+ DASH_ROUTE_PREFIX
+ )
return "OK"
@@ -229,15 +237,15 @@ def health_check():
def print_instructions():
"""Print usage instructions"""
obs_url = f"rtmp://{SERVER_DOMAIN}/live"
- vrc_url = f"rtmp://{SERVER_DOMAIN}/live/{STREAM_HEX}"
+ dash_url = f"https://{SERVER_DOMAIN}{DASH_ROUTE_PREFIX}/manifest.mpd"
print("\n" + "="*80)
print(f"{'OBS TO VRCHAT STREAMING PROXY':^80}")
print("="*80)
print("\n[URLS]")
- print(f" OBS: {obs_url}")
- print(f" VRChat: {vrc_url}")
+ print(f" OBS ingest: {obs_url}")
+ print(f" DASH: {dash_url}")
print("\n[STATUS]")
print(f" Stream is {'ACTIVE' if ffmpeg_process else 'INACTIVE'}")
diff --git a/push.sh b/push.sh
index e144182..7853dbb 100755
--- a/push.sh
+++ b/push.sh
@@ -23,6 +23,7 @@ sudo cp etc/nginx/modules-available/rtmp.conf /etc/nginx/modules-available/
sudo cp etc/nginx/sites-available/yummers.dev /etc/nginx/sites-available/
sudo ln -sf /etc/nginx/sites-available/yummers.dev /etc/nginx/sites-enabled/yummers.dev
sudo cp opt/obsproxy/server.py /opt/obsproxy/
+sudo rm -rf /var/www/streams/*
# Reload systemd daemon and restart obsproxy service
sudo systemctl daemon-reload