feat: redesign portal UX and stabilize web session runtime
This commit is contained in:
19
rdp-proxy/Dockerfile
Normal file
19
rdp-proxy/Dockerfile
Normal file
@@ -0,0 +1,19 @@
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
xvfb \
|
||||
x11vnc \
|
||||
freerdp2-x11 \
|
||||
novnc \
|
||||
websockify \
|
||||
ca-certificates \
|
||||
fonts-dejavu-core \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
EXPOSE 6080
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
87
rdp-proxy/entrypoint.sh
Normal file
87
rdp-proxy/entrypoint.sh
Normal file
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
RDP_HOST="${RDP_HOST:?RDP_HOST is required}"
|
||||
RDP_PORT="${RDP_PORT:-3389}"
|
||||
RDP_USER="${RDP_USER:-}"
|
||||
RDP_PASSWORD="${RDP_PASSWORD:-}"
|
||||
RDP_DOMAIN="${RDP_DOMAIN:-}"
|
||||
RDP_SECURITY="${RDP_SECURITY:-}"
|
||||
SESSION_ID="${SESSION_ID:-unknown}"
|
||||
IDLE_TIMEOUT="${IDLE_TIMEOUT:-1800}"
|
||||
ENABLE_HEARTBEAT="${ENABLE_HEARTBEAT:-1}"
|
||||
TOUCH_PATH="${TOUCH_PATH:-/api/sessions/${SESSION_ID}/touch}"
|
||||
SCREEN_GEOMETRY="${SCREEN_GEOMETRY:-1920x1080x24}"
|
||||
DISPLAY_NUM="${DISPLAY_NUM:-:1}"
|
||||
|
||||
mkdir -p /opt/portal
|
||||
cp -r /usr/share/novnc/* /opt/portal/
|
||||
|
||||
cat > /opt/portal/index.html <<HTML
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>RDP Session</title>
|
||||
<style>html,body,#screen{margin:0;height:100%;background:#111}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="screen"></div>
|
||||
<script type="module">
|
||||
import RFB from './core/rfb.js';
|
||||
const wsBase = location.pathname.replace(/\/+$/, '');
|
||||
const wsUrl = (location.protocol === 'https:' ? 'wss://' : 'ws://') + location.host + wsBase + '/websockify';
|
||||
const rfb = new RFB(document.getElementById('screen'), wsUrl);
|
||||
rfb.viewOnly = false;
|
||||
rfb.scaleViewport = true;
|
||||
rfb.resizeSession = true;
|
||||
const enableHeartbeat = "${ENABLE_HEARTBEAT}" === "1";
|
||||
async function touch() {
|
||||
try {
|
||||
await fetch('${TOUCH_PATH}', {method:'POST', credentials:'include'});
|
||||
} catch(e) {}
|
||||
}
|
||||
if (enableHeartbeat) {
|
||||
setInterval(touch, 60000);
|
||||
touch();
|
||||
}
|
||||
document.addEventListener('contextmenu', (e) => e.preventDefault());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
export DISPLAY="$DISPLAY_NUM"
|
||||
Xvfb "$DISPLAY_NUM" -screen 0 "$SCREEN_GEOMETRY" >/tmp/xvfb.log 2>&1 &
|
||||
sleep 1
|
||||
|
||||
RDP_ARGS=(
|
||||
"/v:${RDP_HOST}:${RDP_PORT}"
|
||||
"/cert:ignore"
|
||||
"/f"
|
||||
"/dynamic-resolution"
|
||||
"/gfx-h264:avc444"
|
||||
"/network:auto"
|
||||
"+clipboard"
|
||||
)
|
||||
|
||||
if [ -n "$RDP_SECURITY" ]; then
|
||||
RDP_ARGS+=("/sec:${RDP_SECURITY}")
|
||||
fi
|
||||
|
||||
if [ -n "$RDP_USER" ]; then
|
||||
RDP_ARGS+=("/u:${RDP_USER}")
|
||||
fi
|
||||
if [ -n "$RDP_PASSWORD" ]; then
|
||||
RDP_ARGS+=("/p:${RDP_PASSWORD}")
|
||||
fi
|
||||
if [ -n "$RDP_DOMAIN" ]; then
|
||||
RDP_ARGS+=("/d:${RDP_DOMAIN}")
|
||||
fi
|
||||
|
||||
xfreerdp "${RDP_ARGS[@]}" >/tmp/xfreerdp.log 2>&1 &
|
||||
|
||||
x11vnc -display "$DISPLAY_NUM" -rfbport 5900 -forever -shared -nopw -noxdamage >/tmp/x11vnc.log 2>&1 &
|
||||
|
||||
exec websockify --verbose --idle-timeout="$IDLE_TIMEOUT" --web=/opt/portal 6080 localhost:5900
|
||||
Reference in New Issue
Block a user