diff --git a/deploy/webtop-docker-compose.yml b/deploy/webtop-docker-compose.yml new file mode 100644 index 0000000..83b7a75 --- /dev/null +++ b/deploy/webtop-docker-compose.yml @@ -0,0 +1,19 @@ +services: + webtop: + image: lscr.io/linuxserver/webtop:ubuntu-xfce + container_name: atlas-webtop + security_opt: + - seccomp:unconfined + environment: + - PUID=0 + - PGID=0 + - TZ=Europe/Amsterdam + - TITLE=Atlas Desktop + - CUSTOM_USER=${WEBTOP_USER} + - PASSWORD=${WEBTOP_PASSWORD} + volumes: + - /opt/atlas/webtop/config:/config + ports: + - "127.0.0.1:8131:3000" + shm_size: "2gb" + restart: unless-stopped diff --git a/docs/remote-desktop.md b/docs/remote-desktop.md new file mode 100644 index 0000000..5652c68 --- /dev/null +++ b/docs/remote-desktop.md @@ -0,0 +1,27 @@ +# Atlas Remote Desktop + +A **real Linux desktop in the browser** — not a web app. Full XFCE on Ubuntu 26.04, +streamed via Selkies/WebRTC, where you can run any application: Claude Code, Chromium, +a terminal, editors, anything you apt-install. + +**URL:** https://desktop.atlascorporation.nl (login at the Caddy edge) + +## Why a real desktop +Unlike a headless server, a desktop has a browser — so the Claude Code OAuth login +flow works normally. Open the terminal, run `claude`, log in through Chromium. Done. + +## Stack +- **Image:** lscr.io/linuxserver/webtop:ubuntu-xfce (Selkies/WebRTC) +- **Bind:** 127.0.0.1:8131 (loopback only — never exposed directly) +- **Edge:** Caddy reverse_proxy + basic_auth (TLS via Let's Encrypt) +- **Persistence:** /opt/atlas/webtop/config (home survives restarts) +- **Pre-installed:** Claude Code CLI (on PATH), Chromium, XFCE terminal; + desktop launchers for Claude + Chromium + +## Compose +See `deploy/webtop-docker-compose.yml`. Credentials live in a local `.env` +(gitignored) and the Caddy basic_auth hash — never committed. + +## Roadmap +- Migrate edge auth from Caddy basic_auth to Authentik SSO (consistent identity) +- Optional: pin Claude to the Max subscription via the in-desktop browser login diff --git a/web/os.html b/web/os.html index 9ac9159..f0f1993 100644 --- a/web/os.html +++ b/web/os.html @@ -153,9 +153,10 @@ var apps=[ {id:"s_bec",name:"Budget Energie",icon:"ti-bolt",c:"#e0a234",url:"https://budgetenergiecoach.nl"}, {id:"s_hki",name:"HKinterCare",icon:"ti-heart",c:"#e2655f",url:"https://hkintercare.nl"}, {id:"s_jea",name:"Jouw Energie",icon:"ti-sun",c:"#e0a234",url:"https://jouwenergieadvies.nl"}, - {id:"s_rm",name:"ReclameMans",icon:"ti-speakerphone",c:"#4ec98a",url:"https://reclamemans.nl"} + {id:"s_rm",name:"ReclameMans",icon:"ti-speakerphone",c:"#4ec98a",url:"https://reclamemans.nl"}, + {id:"desktop",name:"Remote Desktop",icon:"ti-device-desktop",c:"#9b8cf0",url:"https://desktop.atlascorporation.nl"} ]; -var CATS={today:"Cockpit",money:"Cockpit",inbox:"Cockpit",pipeline:"Cockpit",fleet:"Cockpit",control:"Cockpit",auth:"Identity",vault:"Identity",chat:"AI",llm:"AI",mindmap:"AI",leer:"AI",odoo:"Work",cfo:"Work",bank:"Work",paperless:"Work",office:"Work",cal:"Work",files:"Files & Comms",mailadmin:"Files & Comms",relay:"Files & Comms",git:"Ops",n8n:"Ops",uptime:"Ops",mesh:"Ops",map:"Ops",arch:"Ops",s_works:"Sites",s_corp:"Sites",s_agency:"Sites",s_academy:"Sites",s_pos:"Sites",s_hub:"Sites",s_bicos:"Sites",s_bec:"Sites",s_hki:"Sites",s_jea:"Sites",s_rm:"Sites"}; +var CATS={today:"Cockpit",money:"Cockpit",inbox:"Cockpit",pipeline:"Cockpit",fleet:"Cockpit",control:"Cockpit",auth:"Identity",vault:"Identity",chat:"AI",llm:"AI",mindmap:"AI",leer:"AI",odoo:"Work",cfo:"Work",bank:"Work",paperless:"Work",office:"Work",cal:"Work",files:"Files & Comms",mailadmin:"Files & Comms",relay:"Files & Comms",git:"Ops",n8n:"Ops",uptime:"Ops",mesh:"Ops",map:"Ops",arch:"Ops",s_works:"Sites",s_corp:"Sites",s_agency:"Sites",s_academy:"Sites",s_pos:"Sites",s_hub:"Sites",s_bicos:"Sites",s_bec:"Sites",s_hki:"Sites",s_jea:"Sites",s_rm:"Sites",desktop:"Ops"}; function eur(n){try{return new Intl.NumberFormat("nl-NL",{style:"currency",currency:"EUR"}).format(n);}catch(e){return "€"+n;}} function esc(s){return String(s==null?"":s).replace(/[&<>]/g,function(c){return{"&":"&","<":"<",">":">"}[c];});} function netHealth(ok){var w=document.getElementById("tbwifi");if(!w)return;w.style.color=ok?"#4ec98a":"#e2655f";w.className="ti "+(ok?"ti-wifi":"ti-wifi-off");w.title=ok?"Live data connected":"Live data unavailable";}