How to host a website from your home network using Wireguard, Caddy, and a VM. And perhaps why you shouldn't.
Hosting From Home
If you’ve flirted with the idea of running a server in your house,
you’ve probably stumbled across services like Ngrok that let you, with a
single command, get an HTTPs URL that connects to something on your
The idea is simple – someone accesses the URL, hits Ngrok’s servers,
and is then routed to your computer on your home network.
While this is useful, and while there are plenty of tools that help
build tunnels, we
can build this ourselves, and easily host a website (or service, or
anything really), using our own tunnel, built on Wireguard! And we can
setup HTTPs too!
Who Is This For (and Who It Isn’t)
Before we get too far into this, I want to stress this is a niche setup.
Serving something on the public internet from your house means you meet
both of these criteria:
You have complex/unusual hosting needs
You want to share something with a large, public audience
Let’s take each of these one at a time.
If you just want to host a website there’s usually no reason to host
it from your house. Your home internet’s upload speed will pale in
comparison to any datacenter, and any time something happens to your
home internet (power outage, someone else sucks up the bandwidth with a
zoom call, etc), your website will suffer.
If you just want to put something online, there are some excellent (and
inexpensive) website providers. If your website is static (like this one),
Netlify, Github Pages, Cloudflare Pages, Vercel, and Surge are all excellent
options, that will be cheaper (often free) and faster than what we’re discussing
here. Even if you need more than just static files, there are plenty of
providers that will give you anything from basic virtual machines (Linode,
Digital Ocean) to fully managed websites (Squarespace, Wordpress, Wix, etc).
This will probably be cheaper and cause less stress then running it out of your
But there are cases where that doesn’t make sense – where having your
website on your local home network is a good idea. Maybe you’re setting up
Nextcloud, and you want to have access to the existing mountain of data
you already have on your NAS (and paying for extra storage from a
cloud provider would be expensive). Or maybe you’re making some shiny
public dashboard of all your smart home sensors you want to show off.
Or maybe you’re doing it for learning – maybe you want to setup a
cluster of Raspberry Pis and expose them to the world for testing.
That’s fine too!
That said, this setup only makes sense if you are making your website (or
service, or whatever) available to the general public. If you just
want to make your Plex server available on the go, or you want to make a
chat server for you and a few friends, there’s a better solution:
In this model, we don’t need to pay for a VM, and it’s far more secure.
Because all the services are behind Wireguard, even if there’s some
vulnerability in Plex, even if your partner uses the same password for
everything, it doesn’t matter, because to touch any service, you must go
through Wireguard. It’s an easy, safe way to expose services from your
house (it’s how I use my PiHole ad blocker, even when on
If you have an unusual internet setup (such as fixed wireless or
satellite) and/or can’t have inbound ports, we can still use a VM as an
entry point (as we’re doing in this article), and still place everything
behind Wireguard (you would just connect to your VM over Wireguard
instead of open HTTPs).
But, before we proceed, we need to make something clear: we’re
discussing making something available to the entire internet. Again,
there are cases where this makes sense (showing off a demo to someone
before you tear it down, hosting NextCloud for a larger group, etc), but
just remember: you’re connecting the public internet to a thing running
on your home network. If someone breaks in, they’ll be inside your home
network. While there are ways to mitigate this risk (VLANs), this
isn’t optimal. Keep this in mind as you proceed!
Why a Tunnel?
You may have noticed in the previous section that one of the diagrams
had people just connecting to your house directly. Why are we bothering
with a tunnel and paying for a public VM?
Well, there are a couple of reasons for this. The first is safety – if
you host a website directly from your home network, so that when people
type in the address bar they are connect to your home IP address, people
will know your home IP address. Which means they’ll know where you live
(or at least the township). They’ll also be able to potentially unleash
attacks on your home internet connection that aren’t otherwise possible.
Second, hosting HTTPs services at home can be tricky. A lot of
residential ISPs block the ports used for normal inbound web traffic.
We are side-stepping both of these issues with using a Wireguard tunnel.
The only IP address people see will be the one of the public VM in some
datacenter (avoiding the privacy issues), and the connection into our
house will flow through Wireguard (bypassing any ISP port blocks).
To make this work, you’ll need a few things:
A virtual machine from some cloud provider (I’m partial to
DigitalOcean, but any provider will do)
Note: You don’t need a machine with a lot of power or RAM – the
$5/mo option on Digital Ocean works fine.
Be aware of bandwidth – if you’re hosting NextCloud and you’re
going to be moving large files, you should check how your
provider bills for ingress and egress!
Something on your home network where you’re going to host this new
website (a raspberry pi works well here)
A domain name (while not technically required for hosting, we’ll
need it to get a free SSL cert). If you’re just trying this out, you
can grab a free domain from freenom, or use a free dynamic dns
provider like DuckDNS.
To keep this article focused (and not longer than it already is), I’m going to
assume both the virtual machine and the pi (or whatever your home server is) are
already up and running and secured (this means you’ve setup unattended-upgrades
on both of them to keep them updated, right?), and you have a DNS record
pointing to your public virtual machine.
I’ll also assume you already have a web service running on your home
machine that you want to share with the outside world. You should test
this before getting started!
We’ll start by setting up Wireguard to connect the public and private
machines together, then we’ll setup Caddy on the public virtual machines
to automatically give us SSL certificates and to forward connections to
the private machine!
Note: I’m using Ubuntu 20.04 on both machines, but these instructions
should be mostly distro agnostic.
Setting Up Wireguard
Installing Wireguard, especially on Ubuntu, is pretty straightforward:
sudo apt install wireguard
And we’re done. Do this on both the client and server, and now we just
need to configure everything.
Configuring the wireguard server (the public vm)
Once wireguard is installed, we have two tasks – to make the
configuration, and to open up the firewall.
To start, let’s make public and private keys for both the private and
public machines. You can do this on any machine.
wg genkey | tee server_prikey | wg pubkey > server_pubkey
wg genkey | tee client_prikey | wg pubkey > client_pubkey
You now have four files – a client public and private key, and a server
public and private key. We’re going to copy paste these values in into
our config files, and then delete them when done.
The configuration for our public vm (our server) is straightforward. I’m
using the 192.168.201.0/24 subnet for our wireguard network, but feel
free to use any private network of your choosing. In this setup, our
public VM will have it’s wireguard interface set to 192.168.201.1, and
our private system will be 192.168.201.2.
Write a file at /etc/wireguard/wg0.conf as root with the content:
And that’s it. We can enable this interface to be brought up at start by
running systemctl enable --now wg-quick@wg0
We now just need to open a firewall port for Wireguard. Assuming you’re
using ufw (which seems to be the preferred firewall for Ubuntu), you can
open a port with sudo ufw allow 51830/udp.
And you now should be set on the server (at least for the Wireguard
part). Let’s setup the client.
Configuring the Wireguard Client (the private machine)
A Note About Firewalls: I’m assuming the Raspberry Pi running on your
local network does not have any firewall running on it. If it does,
you’ll need to setup rules to allow inbound traffic from the Wireguard
Just like we did on our server, create a client configuration at
Once caddy is installed, the configuration is dead easy. Write the
following to /etc/caddy/Caddyfile:
reverse_proxy 192.168.201.2:[port where your server is running on the pi]
You also might have to open up HTTP and HTTPs ports. Go ahead and run:
sudo ufw allow 80/tcp
sudo ufw allow 443/udp
And that’s it. Restart caddy with systemctl enable --now caddy. And
you’re done. After a few seconds, you’ll be able to go to
https://yourdomain.com, and you’ll see whatever’s being served by the
Pi! Caddy is handling getting an SSL cert for us automatically, so
there’s nothing else to do!
As I said, this is a niche use. There’s plenty of times you might want
to make a website on your local machine public, just for a little while,
to show a friend. Having the ability to use a VM (that you may already
have) and turn it into your own tunnel provider gives you options!
Though they’re options you should review and make sure that they make
sense for you!