Architecture

Viewer Proxy & Auth

🔐 Viewer Proxy & Camera Mode#

First-Person vs Third-Person#

prismarine-viewer sets camera mode when the Node viewer starts — not from a browser query string:

# Third-person (default)
VIEWER_FIRST_PERSON=false

# First-person
VIEWER_FIRST_PERSON=true

Switch: set VIEWER_FIRST_PERSON=true on moincraft-viewerpm2 reload ecosystem.config.cjs --update-envpm2 save.

There is no supported ?view=first on the Prismarine web UI alone without changing server options or running a second viewer process on another port.

Securing /viewer/ Behind Nginx#

The Svelte app proxies /viewer/ to the viewer HTTP server. Put TLS + basic auth on the public hostname while keeping the viewer bound to localhost:

location /viewer/ {
    auth_basic           "Moincraft viewer";
    auth_basic_user_file /etc/nginx/.htpasswd_viewer;
    proxy_pass           http://127.0.0.1:55669/;
    proxy_http_version   1.1;
    proxy_set_header     Upgrade $http_upgrade;
    proxy_set_header     Connection "upgrade";
    proxy_set_header     Host $host;
}

Generate htpasswd:

sudo htpasswd -c /etc/nginx/.htpasswd_viewer youruser

Dashboard Iframe Security#

The dashboard uses VITE_USE_VIEWER_PROXY (default: on) so the iframe hits /viewer/ on the same origin as Vite, avoiding mixed-content issues when the dashboard is HTTPS and the viewer is HTTP.

Without the proxy:

  • Dashboard at https://moincraft.de + viewer at http://moincraft.de:55669 = blocked by browser
  • Per-agent viewer ports always use direct http(s)://<host>:<port> — if the dashboard is HTTPS, these must also be proxied

Full Viewer Config Reference#

PORT=55669                           # web server port
VIEWER_USERNAME=Spectator            # bot login name
VIEWER_VIEW_DISTANCE=8               # chunk radius
VIEWER_FIRST_PERSON=false            # camera mode
VIEWER_RENDER_VERSION=1.21.4         # compat layer for 1.21.11 server
VIEWER_VERSION_FALLBACK=true         # auto-fallback on version kick
VIEWER_RECONNECT_BASE_MS=5000        # reconnect start delay
VIEWER_RECONNECT_MAX_MS=60000        # reconnect cap
VIEWER_RECONNECT_JITTER_MS=1500      # random jitter
VIEWER_INITIAL_CONNECT_JITTER_MS=2000