worker_processes 1; error_log /var/log/nginx/error.log warn; events { worker_connections 768; } http { include /etc/nginx/mime.types; default_type application/octet-stream; access_log /var/log/nginx/access.log; sendfile on; keepalive_timeout 65; gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; # Allow large uploads globally (filebrowser, etc.) client_max_body_size 0; server { listen 80 default_server; server_name _; root /usr/share/nginx/html; index index.html index.htm; # Proxy API requests to backend location /rpc/v1 { proxy_pass http://neode-backend:5959; proxy_http_version 1.1; 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 WebSocket connections location /ws { proxy_pass http://neode-backend:5959; 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 86400; } # Proxy public assets from backend location /public { proxy_pass http://neode-backend:5959; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # Proxy REST API requests location /rest { proxy_pass http://neode-backend:5959; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # ElectrumX UI status (polled by the electrs-ui shell) location /electrs-status { proxy_pass http://neode-backend:5959; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # LND UI endpoints (polled by the lnd-ui shell) location /proxy/ { proxy_pass http://neode-backend:5959; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /lnd-connect-info { proxy_pass http://neode-backend:5959; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # Proxy FileBrowser API to mock backend (demo mode) location /app/filebrowser/ { client_max_body_size 10G; proxy_pass http://neode-backend:5959; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_request_buffering off; } # IndeeHub: reverse-proxy the real site same-origin, strip framing headers, # and rewrite its absolute asset paths (/assets, /, src, href) to the # /app/indeedhub/ prefix so the SPA loads inside the iframe. location /app/indeedhub/ { proxy_pass https://indee.tx1138.com/; proxy_http_version 1.1; proxy_set_header Host indee.tx1138.com; proxy_set_header Accept-Encoding ""; proxy_ssl_server_name on; proxy_hide_header X-Frame-Options; proxy_hide_header Content-Security-Policy; proxy_hide_header Content-Security-Policy-Report-Only; sub_filter_types text/html text/css application/javascript application/json; sub_filter_once off; sub_filter 'href="/' 'href="/app/indeedhub/'; sub_filter 'src="/' 'src="/app/indeedhub/'; sub_filter "href='/" "href='/app/indeedhub/"; sub_filter "src='/" "src='/app/indeedhub/"; sub_filter 'from"/' 'from"/app/indeedhub/'; sub_filter 'url(/' 'url(/app/indeedhub/'; } # Mempool: same approach. NOTE mempool.space is a strict third-party app — # its data/websocket calls may still be blocked; iframe is best-effort. location /app/mempool/ { proxy_pass https://mempool.space/; proxy_http_version 1.1; proxy_set_header Host mempool.space; proxy_set_header Accept-Encoding ""; proxy_ssl_server_name on; proxy_hide_header X-Frame-Options; proxy_hide_header Content-Security-Policy; proxy_hide_header Content-Security-Policy-Report-Only; sub_filter_types text/html text/css application/javascript application/json; sub_filter_once off; sub_filter 'href="/' 'href="/app/mempool/'; sub_filter 'src="/' 'src="/app/mempool/'; sub_filter "href='/" "href='/app/mempool/"; sub_filter "src='/" "src='/app/mempool/"; sub_filter 'from"/' 'from"/app/mempool/'; sub_filter 'url(/' 'url(/app/mempool/'; } # Proxy every other app UI (/app//) to the mock backend, which serves # the per-app mock UIs (bitcoin-ui, electrumx, lnd, fedimint) and the # generic "Not available in the demo" notice for the rest. location /app/ { proxy_pass http://neode-backend:5959; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # Serve AIUI SPA location /aiui/ { alias /usr/share/nginx/html/aiui/; try_files $uri $uri/ =404; location ~* /aiui/assets/ { expires 1y; add_header Cache-Control "public, immutable"; } } # Proxy AIUI API requests (web-search, etc.) to backend location /api/ { proxy_pass http://neode-backend:5959; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # Proxy Ollama (local AI) requests to backend location /aiui/api/ollama/ { proxy_pass http://neode-backend:5959; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_buffering off; proxy_cache off; proxy_read_timeout 300s; proxy_set_header Connection ""; } # Proxy Claude API requests to backend (which handles API key + streaming) location /aiui/api/claude/ { proxy_pass http://neode-backend:5959; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_buffering off; proxy_cache off; proxy_read_timeout 300s; proxy_set_header Connection ""; } # Serve static files location / { try_files $uri $uri/ /index.html; } # Cache static assets location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; } } }