Why I built Vaier

java dev.to

Publishing a homelab service shouldn't take six steps

Every time I wanted to expose a new container in my homelab, I went through the same routine:

  1. Add a WireGuard peer for the machine running the container
  2. Add a Route53 CNAME pointing the subdomain at my edge server
  3. Write a Traefik dynamic-config entry routing that subdomain to the right peer IP and port
  4. Wait for Let's Encrypt to provision the cert
  5. Add an Authelia access rule if the service needed SSO
  6. Add a bookmark somewhere I'd actually find later

Six steps. About fifteen minutes when nothing went wrong, an hour when something did. And the failure mode was always interesting: a Route53 record pointing at a Traefik rule that didn't exist yet, or a Traefik rule for a peer that hadn't actually been registered, or a cert that never provisioned because DNS hadn't propagated, or an Authelia rule that referenced a group I hadn't created.

I'm not a network engineer. I'm just someone who keeps adding services to a homelab. And the friction of those six steps was making me run things on my main server unnecessarily — which is exactly the wrong direction.

So I built Vaier.

The problem with the existing options

Before I wrote a line of code, I tried to use what existed. None of these are bad tools — they're all good at what they do. They just don't do this specific thing.

Cloudflare Tunnel is the obvious starting point: it solves the "expose a service without a public IP" problem cleanly. The trade-off is that all your traffic routes through Cloudflare, which is fine for most people and a non-starter for some. More importantly, Tunnel doesn't really handle the workflow part — you still wire up each service one at a time, manage DNS in their dashboard, and either bring your own auth layer or accept Cloudflare Access. The "let me see all my services on all my peers in one place and publish any of them in one click" workflow isn't what Tunnel is for.

Tailscale Funnel is closer in spirit. If you're already deep in the Tailscale ecosystem, it might be all you need. But Funnel is opinionated about how things get exposed, doesn't gate per-service with SSO, and doesn't touch DNS on your own domain. You're also locked into Tailscale's identity layer for auth, which is great if that fits your model and not great if it doesn't.

Nginx Proxy Manager is the closest functional comparison, and the one I used for a long time. It's a UI on top of the reverse proxy. But it's only the reverse proxy. You still bring your own VPN to reach peers behind NAT, your own DNS automation, and your own SSO layer. And NPM has no notion of "what containers exist on which peer" — it doesn't discover, it just routes whatever you point at it.

Traefik Manager takes a similar angle but again, it's the proxy slice. Not the VPN slice. Not the DNS slice. Not the auth slice.

The pattern across all of them: each tool owns one piece. I wanted one place to click "publish this container" and have all the pieces happen — or none of them.

What Vaier actually does

Vaier is a single web UI and a single docker-compose stack. You bring a Linux box with a public IP (a t3.small works fine), a domain, and optionally AWS credentials. From there:

It manages your WireGuard peers. Any machine you want to host services on — a Raspberry Pi at home, a NUC in your office, a VPS somewhere — registers as a peer. QR codes for phones, .conf files for laptops, compose snippets for servers. Peers don't need public IPs; they reach back to the Vaier server over WireGuard, and that's the only machine that needs to be publicly addressable.

It discovers containers on those peers. Once a peer is connected, Vaier sees what's running on it. You don't manually tell it about every service.

One click publishes a container as an HTTPS subdomain. Pick a container, pick a subdomain, decide whether you want SSO in front of it, click publish. Vaier creates the Route53 record (or shows you the DNS to add manually if your domain is elsewhere), writes the Traefik route, provisions the Let's Encrypt cert, and adds the Authelia rule. All in one transaction.

If any step fails, it rolls everything back. This is the part I care about most. If cert provisioning fails after the DNS record has been created, the DNS gets deleted. If the Authelia rule fails after the Traefik route exists, the Traefik route gets removed. You don't end up with orphan records, stale rules, or half-published services. That used to be most of the cleanup work for me, and now it's none of it.

It auto-switches between LAN and WAN. There's a launchpad dashboard that shows all your published services. When you're on the same network as a peer, the launchpad links go straight to the LAN IP. When you're not, they go through the public route. You don't think about it.

Authelia is managed from the UI. Users, groups, per-service access rules. No YAML wrestling.

Up/down alerts via SMTP. If a peer or a service goes down, you get an email. Same for password resets.

That's it. There's no agent on the peers beyond WireGuard. There's no database — state lives on disk in a way that's easy to back up and inspect. The stack is Java 21 and Spring Boot, which is unfashionable but boring in the way infrastructure should be boring.

What it isn't

Some honest disclaimers, because pretending a tool does everything is how trust gets burned:

  • It's not a Kubernetes replacement. If you're running production workloads with autoscaling and multi-region failover, Vaier is not for you. It's for homelabs and small self-hosted setups.
  • It assumes WireGuard. If you want Tailscale, Headscale, ZeroTier, or another overlay, Vaier won't help you today.
  • It's early. I've been running it on my own homelab for a while, but the public release is recent. There will be bugs. The manual-DNS mode in particular is newer than the Route53 path and has seen less abuse.
  • The AWS coupling for Route53 is optional but real. If you don't use Route53, you use manual DNS mode, which works but is more work the first time.

Why this exists, plainly

I wanted to stop doing the same six-step dance every time I deployed a new toy. I wanted publishing a service to be a single transactional operation — DNS, proxy, cert, auth — that either fully succeeds or fully rolls back. I wanted that operation to work across machines behind NAT without depending on a third party to see my traffic. And I wanted the UI to be obvious enough that if I came back six months later having forgotten everything, I could still publish a new service in under a minute.

Vaier is that. Nothing more, nothing less.

If any of this resonates, the landing page has a quick-start: https://getvaier.github.io/vaier/. The repo is at https://github.com/getvaier/vaier, Apache 2.0. I'd genuinely like to hear what breaks — especially from people running domains outside Route53, or running peers on networks I haven't tested.

Source: dev.to

arrow_back Back to Tutorials