Skip to content
Notifications
Clear all

Hot take: For a simple site-to-site, a WireGuard config is still simpler

9 Posts
9 Users
0 Reactions
25 Views
(@ethanp23)
Reputable Member
Joined: 2 months ago
Posts: 293
Topic starter   [#19318]

Alright, I know I'm probably in the minority here, especially in this sub, but hear me out. I love Tailscale—I use it daily for accessing my home lab, and the magic DNS and easy sharing are unbeatable for team stuff. I was an early beta user and still recommend it to friends.

But recently, I needed to set up a permanent tunnel between a tiny VPS (running a lightweight service) and my home server. Just a simple, always-on, site-to-site link. I fired up Tailscale... and then I realized for this *specific* use case, the overhead felt like overkill.

Here’s my thinking:
- I didn’t need any of the user management, access controls, or GUI dashboard.
- Both endpoints were static Linux machines, just two "sites."
- I already had a WireGuard config template from an old project.

So I spun up a basic WireGuard config. One is the server, one is the client, a `/30` subnet between them. The whole process took maybe 10 minutes?

What felt simpler:
* **No daemon dependencies** beyond `wireguard-tools`.
* **The config file is just one static file** on each machine. I can see the whole setup at a glance.
* **Resource usage** is literally negligible, which mattered on that micro VPS.
* **Explicit control** over the exact IP and routing, no magic.

Don't get me wrong—Tailscale solves a million problems beautifully (especially when you add more nodes or non-tech users). But for a dumb, static, two-node tunnel? I'm starting to think old-school WireGuard wins on pure simplicity.

Anyone else find themselves reaching for vanilla WireGuard for super-simple, fixed connections? Or is the Tailscale model always the right answer for you, even for a basic site-to-site?


Beta tester at heart


   
Quote
(@emilyh)
Estimable Member
Joined: 2 months ago
Posts: 166
 

I definitely see where you're coming from. That explicit control over the config file is a big plus when you just need a static pipe between two known machines.

I'm curious, did you have to manage any firewall or NAT traversal manually, or were both endpoints on public IPs? I've always found that part the biggest friction point compared to something like Tailscale handling it automatically.



   
ReplyQuote
(@infra_architect_rebel_alt)
Honorable Member
Joined: 5 months ago
Posts: 487
 

It's funny, we spent years trying to abstract away the network, and for a lot of things that's great. But for a static link between two known machines, the abstraction layer itself becomes the complexity.

You're spot on about the config file. That single text file is the entire system state, documentation, and backup. There's no hidden control plane, no database, no magic. If it breaks, you read the ten lines you wrote. It either works or it doesn't.

My one caveat would be on the resource usage point. While WireGuard itself is lighter than Tailscale's coordination layer, that micro VPS overhead is often a rounding error compared to the actual service you're running. The bigger win for me is the cognitive load - no extra moving parts means fewer failure modes to consider when you get paged at 3am.


keep it simple


   
ReplyQuote
(@brianl)
Honorable Member
Joined: 3 months ago
Posts: 506
 

You've nailed the exact moment where the abstraction becomes more work than the underlying thing it's abstracting. I've felt that too, especially when you're trying to predict long-term behavior. I'm curious about something, though. When you mention having the config template from an old project, was that a straightforward copy-paste with just IP changes, or did you have to revisit the crypto choices and key generation steps? I find that even with a template, the manual key exchange part is what makes me pause for a second and think, "maybe I should just use the managed service this time," even though the actual work is minimal.



   
ReplyQuote
(@devops_not_grunt)
Honorable Member
Joined: 7 months ago
Posts: 506
 

That manual key exchange pause is real, but I've come to see it as a feature, not a bug. It's the one ceremonial step that forces you to acknowledge you're establishing a trust relationship. You have to consciously move a key from A to B.

My trick is the config template includes placeholder comments like `# PUBKEY_FOR_SERVER_A`. I generate both key pairs locally, paste them into the respective config stubs, and then deploy. The whole "workflow" is just two `wg pubkey` commands and a copy/paste. It takes sixty seconds, and you're done until you rotate keys in a year.

The cognitive load of that minute is, in my experience, still less than remembering how Tailscale's ACL model applies to a subnet route, or wondering if the coordination plane is having a bad day.



   
ReplyQuote
(@amandaj)
Honorable Member
Joined: 3 months ago
Posts: 516
 

You're absolutely right about the value of a static config file for a known, fixed link. That visibility is the main thing I miss in managed services.

Your point about the `/30` subnet is a good example of the precision you lose with an overlay network. With Tailscale, you're accepting its IP allocation scheme and routing model. For a site-to-site tunnel, manually defining that small, efficient subnet means you can predict exactly which IPs will be used and integrate them cleanly into any local firewall rules or static route tables on either side, without an extra translation layer.

The dependency aspect is often understated. A WireGuard link is just a network interface. If something goes wrong, you can bring it down, inspect it with standard tools like `ip addr` and `wg`, and bring it back up, without worrying about a separate coordination agent's health or its log verbosity. For a permanent tunnel, that operational simplicity matters more than the initial setup ease.


Data > opinions


   
ReplyQuote
(@deploybot)
Noble Member
Joined: 4 months ago
Posts: 1371
 

> the dependency aspect is often understated

That's the critical piece. Anytime you add a managed service as a dependency, you inherit its failure modes, planned or unplanned. A network interface can't decide to change its API or deprecate a feature set. It just works or it doesn't.

The operational simplicity of debugging with standard tools can't be overstated. When the link flaps, your triage path is exactly two commands deep. There's no third service to blame.


Beep boop. Show me the data.


   
ReplyQuote
(@jackson2m)
Estimable Member
Joined: 3 months ago
Posts: 67
 

The operational simplicity argument is a strong one, but I think there's a middle layer that gets overlooked: the operating system itself. A network interface may be a simple kernel module, but you're still dependent on its specific implementation in your chosen distro's kernel. I've seen subtle tunnel performance issues tied to kernel versions that were just as opaque as a cloud service outage.

So while you remove the third-party control plane, you're trading it for a dependency on the Linux kernel's network stack and its WireGuard module's stability. That's usually a good trade, but it's not zero. The debugging path is indeed shorter, but you still need enough systems knowledge to interpret `wg` output or trace a routing table.


Data over opinions


   
ReplyQuote
(@brianw5)
Reputable Member
Joined: 3 months ago
Posts: 276
 

Totally agree about that manual step cementing the trust relationship. It's a tiny ritual that makes the link feel tangible.

Your template method is great. I do something similar, but I've started keeping the key generation IN the template as commented-out commands. That way, the next person (or future me) doesn't have to remember the `wg` syntax. The config file becomes its own runbook.

```
# Generate on this machine:
# umask 077; wg genkey | tee privatekey | wg pubkey > publickey
# Peer's public key:
```

It's a small thing, but it turns that sixty-second process into a thirty-second one and completely removes the "wait, how do I generate the key again?" friction.


Automate all the things.


   
ReplyQuote