$ -weight: 600;">sudo -weight: 500;">docker run -d --name rustdesk-hbbs \ ---weight: 500;">restart always \ -p 21115:21115 -p 21116:21116 -p 21116:21116/udp -p 21118:21118 \ -v /opt/rustdesk-server:/root \ rustdesk/rustdesk-server hbbs -weight: 600;">sudo -weight: 500;">docker run -d --name rustdesk-hbbr \ ---weight: 500;">restart always \ -p 21117:21117 -p 21119:21119 \ -v /opt/rustdesk-server:/root \ rustdesk/rustdesk-server hbbr
-weight: 600;">sudo -weight: 500;">docker run -d --name rustdesk-hbbs \ ---weight: 500;">restart always \ -p 21115:21115 -p 21116:21116 -p 21116:21116/udp -p 21118:21118 \ -v /opt/rustdesk-server:/root \ rustdesk/rustdesk-server hbbs -weight: 600;">sudo -weight: 500;">docker run -d --name rustdesk-hbbr \ ---weight: 500;">restart always \ -p 21117:21117 -p 21119:21119 \ -v /opt/rustdesk-server:/root \ rustdesk/rustdesk-server hbbr
-weight: 600;">sudo -weight: 500;">docker run -d --name rustdesk-hbbs \ ---weight: 500;">restart always \ -p 21115:21115 -p 21116:21116 -p 21116:21116/udp -p 21118:21118 \ -v /opt/rustdesk-server:/root \ rustdesk/rustdesk-server hbbs -weight: 600;">sudo -weight: 500;">docker run -d --name rustdesk-hbbr \ ---weight: 500;">restart always \ -p 21117:21117 -p 21119:21119 \ -v /opt/rustdesk-server:/root \ rustdesk/rustdesk-server hbbr
┌───────────────────────────────────────────────────────┐
│ HOMELAB (Ubuntu + RTX 5090) │
│ │
│ Coder Server ──── Cloudflare Tunnel ──── Internet │
│ (systemd, :3000) (TCP/HTTP only) │
│ │
│ RustDesk Client ── Tailscale Mesh ──── MacBook │
│ (systemd) (TCP + UDP) iPhone │
│ │
│ RustDesk Server (Docker, ---weight: 500;">restart always) │
│ ├── hbbs (rendezvous, :21115-21116, :21118) │
│ └── hbbr (relay, :21117, :21119) │
│ │
│ llama-server (Gemma 4, :8080) │
│ Tailscale (systemd) │
│ Cloudflared (systemd, tunnel) │
└───────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────┐
│ HOMELAB (Ubuntu + RTX 5090) │
│ │
│ Coder Server ──── Cloudflare Tunnel ──── Internet │
│ (systemd, :3000) (TCP/HTTP only) │
│ │
│ RustDesk Client ── Tailscale Mesh ──── MacBook │
│ (systemd) (TCP + UDP) iPhone │
│ │
│ RustDesk Server (Docker, ---weight: 500;">restart always) │
│ ├── hbbs (rendezvous, :21115-21116, :21118) │
│ └── hbbr (relay, :21117, :21119) │
│ │
│ llama-server (Gemma 4, :8080) │
│ Tailscale (systemd) │
│ Cloudflared (systemd, tunnel) │
└───────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────┐
│ HOMELAB (Ubuntu + RTX 5090) │
│ │
│ Coder Server ──── Cloudflare Tunnel ──── Internet │
│ (systemd, :3000) (TCP/HTTP only) │
│ │
│ RustDesk Client ── Tailscale Mesh ──── MacBook │
│ (systemd) (TCP + UDP) iPhone │
│ │
│ RustDesk Server (Docker, ---weight: 500;">restart always) │
│ ├── hbbs (rendezvous, :21115-21116, :21118) │
│ └── hbbr (relay, :21117, :21119) │
│ │
│ llama-server (Gemma 4, :8080) │
│ Tailscale (systemd) │
│ Cloudflared (systemd, tunnel) │
└───────────────────────────────────────────────────────┘
Can't load image https://vibescoder.dev/images/downtime-is-a-feature/vercel-dns-ipv4-error.png: fetch failed
Error: Image size cannot be determined.
Export encountered an error on /posts/[slug]/opengraph-image/route
Can't load image https://vibescoder.dev/images/downtime-is-a-feature/vercel-dns-ipv4-error.png: fetch failed
Error: Image size cannot be determined.
Export encountered an error on /posts/[slug]/opengraph-image/route
Can't load image https://vibescoder.dev/images/downtime-is-a-feature/vercel-dns-ipv4-error.png: fetch failed
Error: Image size cannot be determined.
Export encountered an error on /posts/[slug]/opengraph-image/route
<img src={`https://vibescoder.dev${firstImage}`} style={{ width: "100%", height: "100%", objectFit: "cover", opacity: 0.15 }}
/>
<img src={`https://vibescoder.dev${firstImage}`} style={{ width: "100%", height: "100%", objectFit: "cover", opacity: 0.15 }}
/>
<img src={`https://vibescoder.dev${firstImage}`} style={{ width: "100%", height: "100%", objectFit: "cover", opacity: 0.15 }}
/>
const imgPath = path.join(process.cwd(), "public", rawImage);
const buf = fs.readFileSync(imgPath);
const ext = path.extname(rawImage).replace(".", "").toLowerCase();
const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext}`;
firstImage = `data:${mime};base64,${buf.toString("base64")}`;
const imgPath = path.join(process.cwd(), "public", rawImage);
const buf = fs.readFileSync(imgPath);
const ext = path.extname(rawImage).replace(".", "").toLowerCase();
const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext}`;
firstImage = `data:${mime};base64,${buf.toString("base64")}`;
const imgPath = path.join(process.cwd(), "public", rawImage);
const buf = fs.readFileSync(imgPath);
const ext = path.extname(rawImage).replace(".", "").toLowerCase();
const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext}`;
firstImage = `data:${mime};base64,${buf.toString("base64")}`;
case $- in *i*) ;; *) return;; esac
case $- in *i*) ;; *) return;; esac
case $- in *i*) ;; *) return;; esac
-weight: 500;">git config --global credential.helper \ '!f() { echo "username=x-access-token"; echo "password=$(coder external-auth access-token github 2>/dev/null)"; }; f'
-weight: 500;">git config --global credential.helper \ '!f() { echo "username=x-access-token"; echo "password=$(coder external-auth access-token github 2>/dev/null)"; }; f'
-weight: 500;">git config --global credential.helper \ '!f() { echo "username=x-access-token"; echo "password=$(coder external-auth access-token github 2>/dev/null)"; }; f'
resource "coder_agent" "main" { env = { GITHUB_TOKEN = data.coder_external_auth.github.access_token GH_TOKEN = data.coder_external_auth.github.access_token }
}
resource "coder_agent" "main" { env = { GITHUB_TOKEN = data.coder_external_auth.github.access_token GH_TOKEN = data.coder_external_auth.github.access_token }
}
resource "coder_agent" "main" { env = { GITHUB_TOKEN = data.coder_external_auth.github.access_token GH_TOKEN = data.coder_external_auth.github.access_token }
}
const today = new Date().toISOString().split("T")[0];
published = published.replace( /^date:\s*'[^']*'/m, `date: '${today}'`,
);
const today = new Date().toISOString().split("T")[0];
published = published.replace( /^date:\s*'[^']*'/m, `date: '${today}'`,
);
const today = new Date().toISOString().split("T")[0];
published = published.replace( /^date:\s*'[^']*'/m, `date: '${today}'`,
);
resource "docker_container" "workspace" { memory = 8192 # MB — safety net, not a throttle memory_swap = 8192 # equal to memory = no swap for container
}
resource "docker_container" "workspace" { memory = 8192 # MB — safety net, not a throttle memory_swap = 8192 # equal to memory = no swap for container
}
resource "docker_container" "workspace" { memory = 8192 # MB — safety net, not a throttle memory_swap = 8192 # equal to memory = no swap for container
} - Cloudflare Tunnel → HTTP/S services (Coder dashboard, blog)
- Tailscale → everything else (SSH, RustDesk, any UDP/TCP -weight: 500;">service) - Draft created → Claude sets date to the day it generates the content
- Draft sits unpublished for N days
- Someone flips published: false → published: true
- Post appears on the blog sorted by its creation date, not its publish date - 1 trip to Austin that forced the remote access setup
- 4 invisible bugs found and fixed — three of them remotely
- 3 failed Vercel deploys from the OG image chicken-and-egg bug
- 3 layers of broken GitHub auth (credential helper, env var, gh CLI)
- 3 days a post was live with the wrong date before anyone noticed
- ~58 GB RAM available for workspaces after all services running
- 8–12 concurrent active agent sessions the workstation can handle
- 8 GB per-container memory limit as a safety net
- 5 tools evaluated for remote desktop — RustDesk won
- 2 Docker containers for self-hosted RustDesk server
- 5 services confirmed persistent across reboots
- 0 ports exposed to the internet (Tailscale mesh, Cloudflare tunnel)
- ~15 minutes from "the date is wrong" to fix deployed across both repos
- ~30 minutes from "how do I remote desktop" to working iPhone → Linux access
- 1 agent that introduced a bug, then found and fixed it