add VNC desktop container at vnc.quinefoundation.com

Custom Podman image (forge.quinefoundation.com/ironmagma/vnc-desktop) running
TigerVNC + noVNC + openbox, proxied via nginx with ACME TLS and basic auth.
Also switches all arion projects from docker to podman backend.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Philip Peterson 2026-05-25 17:08:15 -08:00
parent 7b0482f2ff
commit d7109b6585
7 changed files with 109 additions and 1 deletions

View file

@ -0,0 +1,18 @@
{ pkgs, ... }:
{
project.name = "vnc-desktop";
services.vnc = {
service = {
image = "forge.quinefoundation.com/ironmagma/vnc-desktop:latest";
container_name = "vnc-desktop";
restart = "unless-stopped";
env_file = [ "/run/agenix/vnc-password" ];
volumes = [
"/root/.ssh:/root/host-ssh:ro"
];
extra_hosts = [ "hetzner-host:host-gateway" ];
ports = [ "127.0.0.1:6080:6080" ];
};
};
}

View file

@ -0,0 +1,3 @@
import <nixpkgs> {
system = "x86_64-linux";
}

View file

@ -66,6 +66,16 @@ in {
file = ./secrets/forgejo-runner-token.age; file = ./secrets/forgejo-runner-token.age;
owner = "root"; owner = "root";
}; };
vnc-password = {
file = ./secrets/vnc-password.age;
owner = "root";
};
vnc-htpasswd = {
file = ./secrets/vnc-htpasswd.age;
owner = "nginx";
};
}; };
environment.systemPackages = [ environment.systemPackages = [
@ -93,9 +103,10 @@ in {
]; ];
virtualisation.arion = { virtualisation.arion = {
backend = "docker"; backend = "podman";
projects.forgejo.settings = import ./arion/arion-compose.nix; projects.forgejo.settings = import ./arion/arion-compose.nix;
projects.riverside.settings = import ./arion-riverside/arion-compose.nix; projects.riverside.settings = import ./arion-riverside/arion-compose.nix;
projects.vnc-desktop.settings = import ./arion-vnc/arion-compose.nix;
}; };
services.gitea-actions-runner.instances."ubuntu" = { services.gitea-actions-runner.instances."ubuntu" = {

View file

@ -200,6 +200,23 @@
}; };
}; };
"vnc.quinefoundation.com" = {
enableACME = true;
forceSSL = true;
basicAuthFile = config.age.secrets.vnc-htpasswd.path;
locations."/" = {
proxyPass = "http://127.0.0.1:6080/";
extraConfig = ''
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400;
'';
};
};
"forge.quinefoundation.com-https" = { "forge.quinefoundation.com-https" = {
serverName = "forge.quinefoundation.com"; serverName = "forge.quinefoundation.com";
enableACME = true; enableACME = true;

View file

@ -17,4 +17,11 @@ in {
# TOKEN=<forgejo runner registration token from Forgejo admin> # TOKEN=<forgejo runner registration token from Forgejo admin>
"./forgejo-runner-token.age".publicKeys = [mainframePublicKey]; "./forgejo-runner-token.age".publicKeys = [mainframePublicKey];
# VNC_PASSWORD=<vnc session password>
"./vnc-password.age".publicKeys = [mainframePublicKey];
# htpasswd-format credentials for nginx basic auth on vnc.quinefoundation.com
# Generate with: htpasswd -n <username>
"./vnc-htpasswd.age".publicKeys = [mainframePublicKey];
} }

View file

@ -0,0 +1,23 @@
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
tigervnc-standalone-server \
tigervnc-common \
novnc \
python3-websockify \
openbox \
xterm \
x11-utils \
xfonts-base \
dbus-x11 \
openssh-client \
&& rm -rf /var/lib/apt/lists/*
COPY start.sh /start.sh
RUN chmod +x /start.sh
EXPOSE 6080
CMD ["/start.sh"]

View file

@ -0,0 +1,29 @@
#!/bin/bash
set -e
mkdir -p /root/.vnc /root/.ssh
chmod 700 /root/.ssh
# Set VNC password from environment
echo "${VNC_PASSWORD:?VNC_PASSWORD must be set}" | vncpasswd -f > /root/.vnc/passwd
chmod 600 /root/.vnc/passwd
# Start Xvnc (headless X server + VNC server in one)
Xvnc :1 \
-rfbport 5901 \
-SecurityTypes VncAuth \
-PasswordFile /root/.vnc/passwd \
-geometry 1280x800 \
-depth 24 \
-AlwaysShared \
&
export DISPLAY=:1
sleep 2
# Start window manager and initial terminal
openbox-session &
xterm &
# Serve noVNC web UI + bridge WebSocket -> VNC
exec websockify --web /usr/share/novnc 6080 localhost:5901