From 6340f4113ea9b3a54f414ccf835bacb181c24603 Mon Sep 17 00:00:00 2001 From: "Josh.5" Date: Sat, 17 Sep 2022 23:28:52 +1200 Subject: [PATCH] Add a Nginx reverse proxy to combine all the used ports into one single port This will allow this web UI to sit nicely behind a reverse proxy. Dynamically set the ports used for the - VNC service - noVNC service - Pulseaudio socket - VNC audio transport websocket Remove all mentions of the above used ports in the Dockerfile. --- Dockerfile | 16 +++++--- Dockerfile.arch | 9 +---- docs/unraid.md | 5 +-- overlay/etc/cont-init.d/90-configure_vnc.sh | 42 ++++++++++++++++++++- overlay/etc/supervisor.d/steam.ini | 2 +- overlay/etc/supervisor.d/vnc.ini | 20 +++++++++- overlay/opt/noVNC/audio.patch | 16 ++++---- overlay/opt/noVNC/nginx.conf | 40 ++++++++++++++++++++ 8 files changed, 121 insertions(+), 29 deletions(-) create mode 100644 overlay/opt/noVNC/nginx.conf diff --git a/Dockerfile b/Dockerfile index d6bc8e8..d11d949 100644 --- a/Dockerfile +++ b/Dockerfile @@ -254,8 +254,18 @@ RUN \ && sed -i '/ document.title =/c\ document.title = "Steam Headless - noVNC";' \ /opt/noVNC/app/ui.js \ && \ + echo "**** Update apt database ****" \ + && apt-get update \ + && \ + echo "**** Install nginx support ****" \ + && apt-get install -y \ + nginx \ + && \ echo "**** Section cleanup ****" \ + && apt-get clean autoclean -y \ + && apt-get autoremove -y \ && rm -rf \ + /var/lib/apt/lists/* \ /tmp/noVNC* \ /tmp/novnc.tar.gz @@ -464,18 +474,12 @@ ENV \ # Configure required ports ENV \ PORT_SSH="2222" \ - PORT_VNC="5900" \ - PORT_AUDIO_STREAM="5901" \ PORT_NOVNC_WEB="8083" \ - PORT_AUDIO_WEBSOCKET="32123" \ NEKO_NAT1TO1="" # Expose the required ports EXPOSE 2222 -EXPOSE 5900 -EXPOSE 5901 EXPOSE 8083 -EXPOSE 32123 # Set entrypoint RUN chmod +x /entrypoint.sh diff --git a/Dockerfile.arch b/Dockerfile.arch index 5f2bb7c..6b2f050 100644 --- a/Dockerfile.arch +++ b/Dockerfile.arch @@ -194,6 +194,7 @@ RUN \ echo # Install noVNC +# TODO: Add nginx ARG NOVNC_VERSION=1.2.0 RUN \ echo "**** Fetch noVNC ****" \ @@ -415,17 +416,11 @@ ENV \ # Configure required ports ENV \ PORT_SSH="2222" \ - PORT_VNC="5900" \ - PORT_AUDIO_STREAM="5901" \ - PORT_NOVNC_WEB="8083" \ - PORT_AUDIO_WEBSOCKET="32123" + PORT_NOVNC_WEB="8083" # Expose the required ports EXPOSE 2222 -EXPOSE 5900 -EXPOSE 5901 EXPOSE 8083 -EXPOSE 32123 # Set entrypoint RUN chmod +x /entrypoint.sh diff --git a/docs/unraid.md b/docs/unraid.md index 35a2b82..cd26fb8 100644 --- a/docs/unraid.md +++ b/docs/unraid.md @@ -45,13 +45,10 @@ Unraid's Linux kernel by default does not have the modules required to support c > __Warning__ > - > Be aware that, by default, this container requires at least 8083, 5900, 5901, 32123, and 2222 available for the WebUI, VNC, Web Audio, and SSH to work. It will also require any ports that Steam requires for Steam Remote Play. + > Be aware that, by default, this container requires at least 8083 and 2222 available for the WebUI and SSH to work. It will also require any ports that Steam requires for Steam Remote Play. You can override the default ports used by the container with these variables: - PORT_SSH (Default: 2222) - - PORT_VNC (Default: 5900) - - PORT_AUDIO_STREAM (Default: 5901) - PORT_NOVNC_WEB (Default: 8083) - - PORT_AUDIO_WEBSOCKET (Default: 32123) 3. No server restart is required, however. Ensure that the **steam-headless** Docker container is recreated after installing the **uinput** plugin for it to be able to detect the newly added module. diff --git a/overlay/etc/cont-init.d/90-configure_vnc.sh b/overlay/etc/cont-init.d/90-configure_vnc.sh index 40acd99..8aa5448 100644 --- a/overlay/etc/cont-init.d/90-configure_vnc.sh +++ b/overlay/etc/cont-init.d/90-configure_vnc.sh @@ -1,10 +1,48 @@ echo "**** Configure VNC ****" +function get_unused_port() { + __start_port=${1} + __start_port=$((__start_port+1)) + for __check_port in $(seq ${__start_port} 65000); do + [[ -z $(netstat -ap 2> /dev/null | grep ${__check_port}) ]] && break; + done + echo ${__check_port} +} + +# Export empty values to start +# Without this, supervisor will not be able to parse the ini configs +export PORT_VNC +export PORT_NOVNC_SERVICE +export PORT_AUDIO_WEBSOCKET +export PORT_AUDIO_STREAM + if ([ "${MODE}" != "s" ] && [ "${MODE}" != "secondary" ]); then if [ ${WEB_UI_MODE} = "vnc" ]; then echo "Enable VNC server" sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisor.d/vnc.ini + + # Configure random ports for VNC service, pulseaudio socket, noVNC service and audio transport websocket + # Note: Ports 32035-32248 are unallocated port ranges. We should be able to find something in here that we can use + # REF: https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?&page=130 + export PORT_VNC=$(get_unused_port 32035) + echo "Configure VNC service port '${PORT_NOVNC_SERVICE}'" + export PORT_NOVNC_SERVICE=$(get_unused_port ${PORT_VNC}) + echo "Configure noVNC service port '${PORT_NOVNC_SERVICE}'" + export PORT_AUDIO_WEBSOCKET=$(get_unused_port ${PORT_NOVNC_SERVICE}) + echo "Configure audio websocket port '${PORT_AUDIO_WEBSOCKET}'" + export PORT_AUDIO_STREAM=$(get_unused_port ${PORT_AUDIO_WEBSOCKET}) + echo "Configure pulseaudio encoded stream port '${PORT_AUDIO_STREAM}'" + + # Configure Nginx proxy for the websocket and VNC + sed -i "s||${USER}|" /opt/noVNC/nginx.conf + sed -i "s||${PORT_NOVNC_WEB}|" /opt/noVNC/nginx.conf + sed -i "s||${PORT_NOVNC_SERVICE}|" /opt/noVNC/nginx.conf + sed -i "s||${PORT_AUDIO_WEBSOCKET}|" /opt/noVNC/nginx.conf + mkdir -p /var/log/vncproxy + chown -R ${USER} /var/log/vncproxy + + if [[ "${ENABLE_VNC_AUDIO}" == "true" ]]; then # Credits for this audio patch: # - https://github.com/novnc/noVNC/issues/302 @@ -12,8 +50,8 @@ if ([ "${MODE}" != "s" ] && [ "${MODE}" != "secondary" ]); then # - https://github.com/calebj/noVNC if [ -f /opt/noVNC/audio.patch ]; then echo "Patching noVNC with audio websocket" - # Enable supervisord script - sed -i "s|32123|${PORT_AUDIO_WEBSOCKET}|" /opt/noVNC/audio.patch + # Update port specification in patch file + sed -i "s||${PORT_AUDIO_WEBSOCKET}|" /opt/noVNC/audio.patch # Apply patch pushd /opt/noVNC/ &> /dev/null patch -p1 --input=/opt/noVNC/audio.patch --batch --quiet diff --git a/overlay/etc/supervisor.d/steam.ini b/overlay/etc/supervisor.d/steam.ini index e4c1ccb..f4ba246 100644 --- a/overlay/etc/supervisor.d/steam.ini +++ b/overlay/etc/supervisor.d/steam.ini @@ -6,7 +6,7 @@ autorestart=true # Retry a restart a few times. # This allows this container to start up before X is ready and restart the process until it becomes available. # Each restart will have a small delay of a few seconds. So 50 attempts should be a few mins. -startretries=50 +startretries=50 priority=50 user=%(ENV_USER)s directory=/home/%(ENV_USER)s diff --git a/overlay/etc/supervisor.d/vnc.ini b/overlay/etc/supervisor.d/vnc.ini index 7e1d3c7..b6dbb9f 100644 --- a/overlay/etc/supervisor.d/vnc.ini +++ b/overlay/etc/supervisor.d/vnc.ini @@ -18,7 +18,8 @@ autostart=false autorestart=true priority=30 user=%(ENV_USER)s -command=/opt/noVNC/utils/launch.sh --vnc localhost:%(ENV_PORT_VNC)s --listen %(ENV_PORT_NOVNC_WEB)s +# /opt/noVNC/utils/launch.sh --vnc localhost:${PORT_VNC} --listen ${PORT_NOVNC_SERVICE} +command=/opt/noVNC/utils/launch.sh --vnc localhost:%(ENV_PORT_VNC)s --listen %(ENV_PORT_NOVNC_SERVICE)s environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s" stopsignal=INT stdout_logfile=/home/%(ENV_USER)s/.cache/log/novnc.log @@ -27,3 +28,20 @@ stdout_logfile_backups=7 stderr_logfile=/home/%(ENV_USER)s/.cache/log/novnc.err.log stderr_logfile_maxbytes=10MB stderr_logfile_backups=7 + +[program:vncproxy] +autostart=false +autorestart=true +priority=30 +numprocs=1 +startsecs=0 +user=%(ENV_USER)s +command=/usr/sbin/nginx -c /opt/noVNC/nginx.conf +environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s" +stopsignal=INT +stdout_logfile=/home/%(ENV_USER)s/.cache/log/vncproxy.log +stdout_logfile_maxbytes=10MB +stdout_logfile_backups=7 +stderr_logfile=/home/%(ENV_USER)s/.cache/log/vncproxy.err.log +stderr_logfile_maxbytes=10MB +stderr_logfile_backups=7 diff --git a/overlay/opt/noVNC/audio.patch b/overlay/opt/noVNC/audio.patch index 8f31b12..71a86a1 100644 --- a/overlay/opt/noVNC/audio.patch +++ b/overlay/opt/noVNC/audio.patch @@ -102,14 +102,14 @@ index cb6a9fd..4d599e1 100644 UI.rfb.focus(); + + let audio_url; -+ let host = window.location.hostname; -+ let port = 32123; ++ // let host = window.location.hostname; ++ // let port = ''; + if (window.location.protocol === "https:") { + audio_url = 'wss'; + } else { + audio_url = 'ws'; + } -+ audio_url += '://' + host + ':' + port; ++ audio_url += '://' + window.location.host + '/audiowebsock'; + + UI.webaudio = new WebAudio(audio_url); + UI.toggleAudio(); @@ -326,14 +326,14 @@ index 8e2f5cb..d3cf6ab 100644 // successfully connected to a server function connectedToServer(e) { + let audio_url; -+ let host = window.location.hostname; -+ let port = 32123; ++ // let host = window.location.hostname; ++ // let port = ''; + if (window.location.protocol === "https:") { + audio_url = 'wss'; + } else { + audio_url = 'ws'; + } -+ audio_url += '://' + host + ':' + port; ++ audio_url += '://' + window.location.host + '/audiowebsock'; + + wa = new WebAudio(audio_url); + document.getElementById('toggleAudioButton').style.display = "block"; @@ -360,7 +360,7 @@ index 8e2f5cb..d3cf6ab 100644 + if (wa.connected) { + console.log('Stopping audio...') + wa.stop(); -+ document.getElementById('toggleAudioButton').innerText = "Enable Audio (requires access to port 32123)"; ++ document.getElementById('toggleAudioButton').innerText = "Enable Audio"; + } else { + console.log('Starting audio websocket on: ' + audio_url) + wa.start(); @@ -410,7 +410,7 @@ index 8e2f5cb..d3cf6ab 100644
-+
Enable Audio (requires access to port 32123)
++
Enable Audio
Loading
Send CtrlAltDel
diff --git a/overlay/opt/noVNC/nginx.conf b/overlay/opt/noVNC/nginx.conf new file mode 100644 index 0000000..5b408f4 --- /dev/null +++ b/overlay/opt/noVNC/nginx.conf @@ -0,0 +1,40 @@ +daemon off; +worker_processes auto; +pid /tmp/vncproxy.pid; +error_log /home//.cache/log/vncproxy.err.log; + +events { +} + +http { + server { + listen default_server; + + access_log /home//.cache/log/vncproxy.log; + client_body_temp_path /tmp/client_body; + fastcgi_temp_path /tmp/fastcgi_temp; + proxy_temp_path /tmp/proxy_temp; + scgi_temp_path /tmp/scgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + + location / { + proxy_pass http://127.0.0.1:/; + } + + location /websockify { + proxy_pass http://127.0.0.1:/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + } + + location /audiowebsock { + proxy_pass http://127.0.0.1:/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + } + } +}