diff --git a/apps/docs/docs.json b/apps/docs/docs.json
index cae5622a0..2e00ba2ee 100644
--- a/apps/docs/docs.json
+++ b/apps/docs/docs.json
@@ -31,7 +31,7 @@
"groups": [
{
"group": "Getting Started",
- "pages": ["index", "self-hosting"]
+ "pages": ["index", "self-hosting", "homelab"]
},
{
"group": "Using Roomote",
diff --git a/apps/docs/homelab.mdx b/apps/docs/homelab.mdx
new file mode 100644
index 000000000..68b88ebfc
--- /dev/null
+++ b/apps/docs/homelab.mdx
@@ -0,0 +1,252 @@
+---
+title: Homelab deployment
+icon: house-plug
+description: Run Roomote on a Proxmox VM or another Linux server in your homelab.
+---
+
+Run Roomote on hardware you control with a dedicated Linux VM, private
+administration over Tailscale, and a public HTTPS origin for provider callbacks
+and task previews.
+
+This guide uses **Proxmox VE with a Debian or Ubuntu VM** as the worked example.
+Proxmox and Tailscale are not Roomote requirements: a bare-metal Linux server,
+another hypervisor, WireGuard, or a conventional VPN can provide the same
+roles.
+
+
+ Use a full virtual machine rather than an LXC container for the default Docker
+ sandbox provider. Roomote depends on Docker networking, cgroups, packet-filter
+ rules, and writable-layer quotas that are much easier to operate reliably in
+ a VM. LXC installations require host-specific privileged-container changes
+ and are not covered by this guide.
+
+
+## Plan the deployment
+
+The recommended homelab shape separates private administration from public
+application traffic:
+
+- **Proxmox VM:** runs Roomote, its datastores, and the default Docker task
+ sandboxes
+- **Tailscale:** provides private SSH and administrative access to the VM
+- **Public HTTPS origin:** receives source-control and communications-provider
+ callbacks and serves links generated by Roomote
+- **Caddy:** terminates traffic for the application and task preview hostnames
+
+Roomote supports x86_64 and arm64. The installer requires at least 4 GB of RAM.
+For a deployment that runs Docker task sandboxes on the same host, start with:
+
+| Resource | Recommended starting point |
+| --- | --- |
+| CPU | 4 vCPU, host CPU type |
+| Memory | 8 GB |
+| Disk | 60 GB or more on quota-capable storage |
+| OS | Debian 12 or later, or Ubuntu 24.04 LTS |
+
+The default limit for each Docker task is 2 CPUs, 4 GiB of memory, and a 20 GiB
+writable layer. Increase the VM resources for concurrent or Docker-heavy tasks,
+or use a [hosted sandbox provider](/compute) so task workloads do not compete
+with the Roomote services.
+
+## Create the Proxmox VM
+
+Create a VM from a Debian or Ubuntu cloud image or installation ISO:
+
+1. allocate at least 4 vCPU, 8 GB RAM, and 60 GB of disk
+2. set the CPU type to `host` and use VirtIO for disk and networking
+3. install and enable `qemu-guest-agent`
+4. assign a DHCP reservation or static address on the LAN
+5. enable SSH and apply operating-system updates
+
+A bare-metal mini PC, an existing Debian or Ubuntu server, or a VM on another
+hypervisor works too. The important boundary is a clean Linux host where Docker
+Engine and its networking and storage controls can operate normally.
+
+## Add private administration with Tailscale
+
+Install Tailscale on the VM using the
+[official Linux instructions](https://tailscale.com/kb/1031/install-linux), then
+confirm you can reach the host over its tailnet address before changing router
+or firewall rules. Use Tailscale SSH or regular SSH over the tailnet for host
+administration.
+
+Tailscale does not replace Roomote's public application origin. GitHub, Slack,
+and other providers must reach callbacks from outside your tailnet. Live task
+previews also use per-task hostnames, including wildcard preview DNS in the
+normal production configuration.
+
+
+ Docker task sandboxes block private, link-local, shared-address, cloud
+ metadata, and Tailscale ranges by default. A repository hosted only on your
+ LAN or tailnet may be reachable from the VM but unreachable from a Roomote
+ task. Give self-hosted GitLab or Gitea a public, worker-reachable hostname
+ instead of disabling the sandbox network guard.
+
+
+## Choose public ingress
+
+Choose one stable hostname before completing the setup wizard. Changing it
+later also means updating source-control, sign-in, and communications-provider
+redirect and webhook URLs.
+
+| Path | Best for | Tradeoffs |
+| --- | --- | --- |
+| Public DNS and port forwarding | Public IPv4, router control, and the simplest data path | Requires forwarding ports 80 and 443; dynamic addresses need DDNS |
+| Cloudflare Tunnel | CGNAT or networks where inbound ports should stay closed | Requires tunnel and wildcard-hostname configuration |
+| Tailscale Funnel | A limited public trial without router changes | Does not provide the wildcard hostname model needed for full live previews |
+
+### Public DNS and port forwarding
+
+Create DNS records for the application, preview root, and wildcard previews:
+
+```text
+roomote.example.com A/AAAA
+preview.roomote.example.com A/AAAA
+*.preview.roomote.example.com A/AAAA
+```
+
+Forward TCP ports 80 and 443 from the router to the VM, then run:
+
+```sh
+curl -fsSL https://get.roomote.dev | bash -s -- \
+ --domain roomote.example.com
+```
+
+The installer defaults the preview root to `preview.`. Use
+`--preview-domain ` when your DNS layout differs. If the public address
+changes, configure DDNS for all three records. This path does not work behind
+carrier-grade NAT unless the ISP supplies a public address.
+
+### Cloudflare Tunnel
+
+Cloudflare Tunnel can publish Roomote without forwarding inbound router ports.
+Install Roomote with Caddy's internal TLS mode because Cloudflare terminates the
+public certificate:
+
+```sh
+curl -fsSL https://get.roomote.dev | bash -s -- \
+ --domain roomote.example.com \
+ --tls-mode internal
+```
+
+Route both the application hostname and preview wildcard through the same Caddy
+instance rather than routing directly to individual Roomote containers. Standard
+Cloudflare certificates require Roomote's flat preview-hostname layout; follow
+the canonical
+[Cloudflare Tunnel and flat preview hostname configuration](https://github.com/RooCodeInc/Roomote/blob/main/SELF_HOSTING.md#flat-preview-hostnames)
+for the required environment values, tunnel ingress, origin TLS setting, and
+**Match SNI to Host** option. Apply those values in `/opt/roomote/.env` and run
+`sudo roomote up` before testing or exposing task previews; the install command
+above otherwise retains the default nested preview hostname layout.
+
+### Tailscale Funnel
+
+Tailscale Funnel can expose a stable tailnet hostname to public callback
+providers, but it does not support Roomote's normal wildcard preview hostname
+layout. Treat it as a limited dashboard and callback trial, not the default
+full deployment path. Use public DNS or Cloudflare Tunnel when users need live
+task previews.
+
+## Let a local agent prepare the host
+
+Paste the following prompt into a local coding agent running on the VM or one
+that can SSH to it. The agent prepares the host and installer; you complete
+credential and authorization steps in Roomote's browser wizard.
+
+```text
+Set up a self-hosted Roomote deployment on this homelab server.
+
+Safety and scope:
+- Work only on a dedicated Debian 12+ or Ubuntu 24.04+ VM or bare-metal host.
+- Stop if this is an LXC container or if fewer than 4 GB RAM or 40 GB free disk
+ are available. Warn me and ask before continuing if other production
+ workloads share the host.
+- Explain changes before using sudo. Do not disable the firewall or expose
+ database, Redis, object-storage, API, or queue-dashboard ports.
+- Never ask me to paste model, GitHub, Slack, or other provider secrets into
+ chat or the shell. Those belong in Roomote's browser setup wizard.
+
+Process:
+1. Report the OS, architecture, CPU count, memory, free disk, default route,
+ public IPv4 detection result, and current Docker/storage configuration if
+ Docker is already installed. Do not change anything yet.
+2. Ask me to choose one ingress path: public DNS plus ports 80/443, or
+ Cloudflare Tunnel. If I am behind CGNAT, recommend Cloudflare Tunnel. Ask for
+ the final application domain and optional preview domain.
+3. Ask whether to install Tailscale for private SSH/admin access. If approved,
+ use Tailscale's official Linux package instructions and confirm access. Do
+ not treat the tailnet hostname as Roomote's public application origin.
+4. For public DNS, tell me the exact app, preview, and wildcard DNS records and
+ router forwards I must create, then wait for me. Verify public DNS and ports
+ from outside the LAN where possible. For Cloudflare Tunnel, guide me through
+ creating the app and wildcard public hostnames without asking me to reveal a
+ tunnel token, and use Roomote's documented internal-TLS and flat-preview
+ configuration.
+5. Download https://get.roomote.dev to a temporary file, show me the file path
+ and the exact installer flags you will use, and ask me to inspect it before
+ approval. Then run it with --domain and, for Cloudflare Tunnel, --tls-mode
+ internal. Do not write a new installer or manually recreate the Compose
+ stack.
+6. Run `sudo roomote status`. If healthy, tell me to run `sudo roomote
+ setup-url` in a separate trusted terminal and open the result. Do not print,
+ capture, or repeat the tokenized URL in agent output or transcripts. Stop
+ while I complete sign-in, source control, inference, communications, and
+ environment setup in the browser.
+7. After I confirm setup is complete, validate Docker's writable-layer quota
+ support, a small Roomote task, repository cloning, artifact upload, and a
+ configured preview. Summarize any failure and the relevant `roomote logs`
+ output without printing secrets.
+```
+
+## Complete setup in the browser
+
+The installer sets up Docker, Compose, generated secrets, Caddy, the Roomote
+services, a systemd unit, and the `roomote` host CLI. When it finishes, open the
+tokenized setup URL it prints and configure:
+
+1. the first admin account
+2. a source-control provider and repository access
+3. a ChatGPT subscription or inference provider
+4. Docker or a hosted sandbox provider
+5. an optional communications provider such as Slack
+6. the first environment and Roomote task
+
+Keep provider credentials in the setup wizard or your deployment secret store,
+not in shell history or an agent conversation.
+
+## Verify the homelab path
+
+After setup:
+
+1. run `roomote status` on the VM and confirm the services are healthy
+2. open the public Roomote URL from a device outside the home network
+3. confirm the expected repositories appear in Roomote
+4. validate the sandbox provider from **Settings > Sandboxes**
+5. run a small task and confirm it clones, executes, and uploads an artifact
+6. test a configured live preview from outside the home network
+7. if configured, mention the Roomote app in Slack and confirm it replies
+
+Common homelab failures include:
+
+- **The public URL works on cellular but not on Wi-Fi.** The router may not
+ support hairpin NAT. Add split-horizon DNS for LAN clients or use a resolver
+ that returns the correct internal route.
+- **An `sslip.io` hostname does not resolve on the LAN.** DNS-rebind protection
+ may reject names that resolve to private addresses. Use a domain you control
+ or allow the exact hostname in the local resolver.
+- **Certificates never issue.** Confirm public DNS, router forwarding, and host
+ firewall rules for ports 80 and 443. With a tunnel, use `--tls-mode internal`
+ and check the tunnel-to-Caddy origin TLS settings.
+- **Port forwarding has no effect.** Compare the router WAN address with an
+ external public-IP check. Different addresses usually indicate CGNAT; use a
+ tunnel or request a public address from the ISP.
+- **A task cannot clone a LAN repository.** Use a public, worker-reachable
+ source-control hostname. Do not remove the sandbox private-network guard.
+
+## Back up and update
+
+Use `roomote backup`, `roomote upgrade`, and `roomote rollback` for supported
+day-2 operations. A Proxmox snapshot is useful before host maintenance, but it
+does not replace an encrypted Roomote backup stored off the VM with its
+passphrase stored separately. See [Self-hosting](/self-hosting#day-2-operations)
+for backup, restore, and upgrade behavior.
diff --git a/apps/docs/self-hosting.mdx b/apps/docs/self-hosting.mdx
index ecad66e91..5537dcf43 100644
--- a/apps/docs/self-hosting.mdx
+++ b/apps/docs/self-hosting.mdx
@@ -29,6 +29,10 @@ communications, sandbox, and other tools Roomote needs to do useful work.
- **Your own server** gives you the most infrastructure control with the
one-command installer below.
+Running Roomote on Proxmox or another server at home? Follow the
+[Homelab deployment guide](/homelab) for VM sizing, Tailscale administration,
+public ingress, and a prompt that a local agent can follow.
+
By the end of setup, you should have a reachable Roomote URL, sign-in, a
source-control provider, a ChatGPT subscription or inference provider, at least
one environment, and a first reviewable Roomote task.