Files
XC_VM/lb_configs/nginx.conf
T
Divarion-D 6d9cd5821c fix(nginx): add LB loopback admin routes and correct Public docroot case
LoadBalancer nginx had no ^/admin/ location, so when a server higher in
the tree pulled a stream whose source is an LB, the LB returned 404 for
/admin/{live,timeshift,thumb,vod} before the request ever reached PHP.
The MAIN→LB direction worked (MAIN has the route); LB→MAIN was silently
broken — stream shown down, nothing in the panel logs.

Add a reduced admin location exposing ONLY the loopback handlers
(live|timeshift|thumb|vod) — not index|api|proxy_api — so the admin
panel itself is never served from a LoadBalancer. Mirrors the MAIN
admin gateway block.

Also fix a PSR-4 rename miss: the directory rename public/ → Public/
(1a296d09) updated src/bin/nginx/conf/nginx.conf but left
lb_configs/nginx.conf pointing at /home/xc_vm/public/ everywhere
(root, stream, progress, api). On a case-sensitive fresh LB install the
on-disk path is Public/, so every SCRIPT_FILENAME 404'd — all LB
streaming broke, not just loopback. Repoint the 8 filesystem paths to
Public/; SCRIPT_NAME stays /public/ (logical CGI path, matches MAIN).
2026-06-26 20:00:30 +03:00

262 lines
9.0 KiB
Nginx Configuration File

user xc_vm;
worker_processes auto;
worker_rlimit_nofile 300000;
events {
worker_connections 16000;
use epoll;
multi_accept on;
}
thread_pool pool_xc_vm threads=32 max_queue=0;
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
reset_timedout_connection on;
gzip off;
fastcgi_read_timeout 200;
access_log off;
error_log /dev/null;
keepalive_timeout 10;
include balance.conf;
send_timeout 20m;
sendfile_max_chunk 512k;
lingering_close off;
aio threads=pool_xc_vm;
client_body_timeout 13s;
client_header_timeout 13s;
client_max_body_size 8m;
real_ip_header X-Forwarded-For;
include realip_cdn.conf;
include realip_cloudflare.conf;
include realip_xc_vm.conf;
include limit.conf;
limit_req_zone $binary_remote_addr zone=one:30m rate=20r/s;
server {
include ports/*.conf;
include ssl.conf;
include custom.conf;
index index.php index.html index.htm;
try_files $uri $uri.html $uri/ @extensionless-php;
root /home/xc_vm/Public/;
server_tokens off;
chunked_transfer_encoding off;
resolver 1.1.1.1 1.0.0.1 valid=300s;
resolver_timeout 5s;
absolute_redirect off;
if ($request_method !~ ^(GET|POST)$) {
return 200;
}
location ^~ /.well-known/acme-challenge/ {
root /home/xc_vm/certbot-webroot;
try_files $uri =404;
}
rewrite_log on;
rewrite ^/key/(?<token>[^/]*)$ /stream/key?token=$token break;
rewrite ^/hls/(?<token>[^/]*)$ /stream/segment?token=$token break;
rewrite ^/tsauth/(?<token>[^/]*)$ /stream/timeshift?token=$token break;
rewrite ^/thauth/(?<token>[^/]*)$ /stream/thumb?token=$token break;
rewrite ^/auth/(?<token>[^/]*)$ /stream/live?token=$token break;
rewrite ^/vauth/(?<token>[^/]*)$ /stream/vod?token=$token break;
rewrite ^/subauth/(?<token>[^/]*)$ /stream/subtitle?token=$token break;
location = /streaming/rtmp.php {
return 302 /stream/rtmp?$args;
}
# ─── Legacy Stream PHP Compatibility (no direct www execution) ──
location ~ ^/stream/(auth|key|segment|live|vod|timeshift|thumb|subtitle|rtmp)\.php$ {
return 302 /stream/$1?$args;
}
location = /probe.php {
return 302 /stream/probe?$args;
}
# ─── Streaming Hot Path → Stream Gateway ─────────────────
location ~ ^/stream/(auth|key|segment|live|vod|timeshift|thumb|subtitle|rtmp|probe)$ {
limit_req zone=one burst=8;
include limit_queue.conf;
fastcgi_index index.php;
fastcgi_pass php;
include fastcgi_params;
fastcgi_buffering on;
fastcgi_buffers 96 32k;
fastcgi_buffer_size 32k;
fastcgi_max_temp_file_size 0;
fastcgi_keep_conn on;
fastcgi_param SCRIPT_FILENAME /home/xc_vm/Public/stream/index.php;
fastcgi_param SCRIPT_NAME /public/stream/index.php;
fastcgi_param XC_STREAM $1;
}
# ─── Loopback handlers only → Admin Gateway ──────────────
# A server higher in the tree pulls streams whose source is this LB
# via /admin/{live,timeshift,thumb,vod}. Expose ONLY those handlers —
# never index|api|proxy_api — so the admin panel is not served from a LB.
location ~ ^/admin/(live|timeshift|thumb|vod)$ {
limit_req zone=one burst=8;
include limit_queue.conf;
fastcgi_index index.php;
fastcgi_pass php;
include fastcgi_params;
fastcgi_buffering on;
fastcgi_buffers 128 32k;
fastcgi_buffer_size 32k;
fastcgi_busy_buffers_size 128k;
fastcgi_max_temp_file_size 0;
fastcgi_keep_conn on;
fastcgi_param SCRIPT_FILENAME /home/xc_vm/Public/admin/index.php;
fastcgi_param SCRIPT_NAME /public/admin/index.php;
fastcgi_param XC_ADMIN $1;
}
location ~ ^/admin/(live|timeshift|thumb|vod)\.php$ {
return 302 /admin/$1?$args;
}
location ~* ^/images/(.*/)?index\.html$ {
return 404;
}
location ^~ /images/ {
alias /home/xc_vm/storage/images/;
location ~* \.(php|php\d*|phtml|phar)$ {
return 403;
}
}
location ~ ^/status$ {
allow 127.0.0.1;
deny all;
fastcgi_index index.php;
fastcgi_pass php;
include fastcgi_params;
fastcgi_buffering on;
fastcgi_buffers 96 32k;
fastcgi_buffer_size 32k;
fastcgi_max_temp_file_size 0;
fastcgi_keep_conn on;
fastcgi_param SCRIPT_FILENAME /home/xc_vm/Public/stream/index.php;
fastcgi_param SCRIPT_NAME /public/stream/index.php;
fastcgi_param XC_STREAM status;
}
location /nginx_status {
allow 127.0.0.1;
deny all;
stub_status on;
}
location = /progress {
limit_req zone=one burst=8;
include limit_queue.conf;
fastcgi_index index.php;
fastcgi_pass php;
include fastcgi_params;
fastcgi_buffering on;
fastcgi_buffers 96 32k;
fastcgi_buffer_size 32k;
fastcgi_max_temp_file_size 0;
fastcgi_keep_conn on;
fastcgi_param SCRIPT_FILENAME /home/xc_vm/Public/progress/index.php;
fastcgi_param SCRIPT_NAME /public/progress/index.php;
}
location = /progress.php {
return 302 /progress?$args;
}
# ─── Streaming API → Front Controller ───────────────────────
location ~ ^/api/(player_api|enigma2|xplugin|epg|playlist)$ {
limit_req zone=one burst=8;
include limit_queue.conf;
fastcgi_index index.php;
fastcgi_pass php;
include fastcgi_params;
fastcgi_buffering on;
fastcgi_buffers 96 32k;
fastcgi_buffer_size 32k;
fastcgi_max_temp_file_size 0;
fastcgi_keep_conn on;
fastcgi_param SCRIPT_FILENAME /home/xc_vm/Public/index.php;
fastcgi_param SCRIPT_NAME /public/index.php;
fastcgi_param XC_SCOPE api;
fastcgi_param XC_API $1;
}
location ~ ^/(player_api|enigma2|xplugin|epg|playlist)\.php$ {
limit_req zone=one burst=8;
include limit_queue.conf;
fastcgi_index index.php;
fastcgi_pass php;
include fastcgi_params;
fastcgi_buffering on;
fastcgi_buffers 96 32k;
fastcgi_buffer_size 32k;
fastcgi_max_temp_file_size 0;
fastcgi_keep_conn on;
fastcgi_param SCRIPT_FILENAME /home/xc_vm/Public/index.php;
fastcgi_param SCRIPT_NAME /public/index.php;
fastcgi_param XC_SCOPE api;
fastcgi_param XC_API $1;
}
# ─── Internal API → Front Controller (server-to-server) ────
# Аутентификация: InternalApiController проверяет password + IP whitelist
location = /api {
fastcgi_index index.php;
fastcgi_pass php;
include fastcgi_params;
fastcgi_buffering on;
fastcgi_buffers 96 32k;
fastcgi_buffer_size 32k;
fastcgi_max_temp_file_size 0;
fastcgi_keep_conn on;
fastcgi_param SCRIPT_FILENAME /home/xc_vm/Public/index.php;
fastcgi_param SCRIPT_NAME /public/index.php;
fastcgi_param XC_SCOPE api;
fastcgi_param XC_API internal;
}
location = /api.php {
fastcgi_index index.php;
fastcgi_pass php;
include fastcgi_params;
fastcgi_buffering on;
fastcgi_buffers 96 32k;
fastcgi_buffer_size 32k;
fastcgi_max_temp_file_size 0;
fastcgi_keep_conn on;
fastcgi_param SCRIPT_FILENAME /home/xc_vm/Public/index.php;
fastcgi_param SCRIPT_NAME /public/index.php;
fastcgi_param XC_SCOPE api;
fastcgi_param XC_API internal;
}
# ─── Ministra Legacy Portal (L-6 pending) ────────────────
location = /c/portal.php {
return 404;
}
location = /portal.php {
return 404;
}
location ~ \.php$ {
return 404;
}
location @extensionless-php {
return 404;
}
}
}