One of the things many of us struggle with when setting friends and
family up with Linux is remote support. Commercial solutions like
[RealVNC](https://www.realvnc.com/) and [RustDesk](https://rustdesk.com/) do exist and function very well, but are often more
expensive than we would like for answering the odd "I can't get Facebook
open!" support call. I've been on the lookout for suitable alternatives
for a couple years but nothing has been satisfying. Because of this, I
have held off on setting others up with any Linux distribution, even the
particularly user-friendly options such as [Linux Mint](https://linuxmint.com/) and [elementary OS;](https://elementary.io/)
if I'm going drop someone in an unfamiliar environment, I want to be
able to help with any issue within a couple hours, not days and
_certainly_ not weeks.
[Episode 421 of LINUX Unplugged](https://linuxunplugged.com/421) gave me an awesome idea to use [Nebula,](https://github.com/slackhq/nebula) a
networking tool created by Slack, [X11vnc,](https://libvnc.github.io/) a very minimal VNC server, and
[Remmina,](https://remmina.org/) a libre remote access tool available in pretty much every Linux
distribution, to set up a scalable, secure, and simple setup reminiscent
of products like RealVNC.
## Nebula {#nebula}
The first part of our stack is Nebula, the tool that creates a network
between all of our devices. With traditional VPNs, you have a client
with a persistent connection to a central VPN server and other clients
can communicate with the first by going through that central server.
This works wonderfully in most situations, but there are a lot of
latency and bandwidth restrictions that would make remote support an
unpleasant experience. Instead of this model, what we want is a _mesh_
network, where each client can connect directly to one another _without_
going through a central system and slowing things down. This is where
Nebula comes in.
In Nebula's terminology, clients are referred to as _nodes_ and central
servers are referred to as _lighthouses_, so those are the terms I'll use
going forward.
Mesh networks are usually only possible when dealing with devices that
have static IP addresses. Each node has to know _how_ to connect with the
other nodes; John can't meet up with Bob when Bob moves every other day
without notifying anyone of his new address. This wouldn't be a problem
if Bob phoned Jill and told her where he was moving; John would call
Jill, Jill would tell him where Bob is, and the two would be able to
find each other
With Nebula, nodes are Bob and John and Jill is a lighthouse. Each node
connects to a lighthouse and the lighthouse tells the nodes how to
connect with one another when they ask. It _facilitates_ the P2P
connection then _backs out of the way_ so the two nodes can communicate
directly with each other.
It allows any node to connect with any other node on any network from
anywhere in the world, as long as one lighthouse is accessible that
knows the connection details for both peers.
### Getting started {#getting-started}
The _best_ resource is [the official documentation,](https://github.com/slackhq/nebula) but I'll describe the
process here as well.
After [installing the required packages,](https://github.com/slackhq/nebula#1-the-nebula-binaries-or-distribution-packages-for-your-specific-platform-specifically-youll-need-nebula-cert-and-the-specific-nebula-binary-for-each-platform-you-use) make sure you have a VPS with a
static IP address to use as a lighthouse. If you want something dirt
cheap, I would recommend one of the small plans from [BuyVM.](https://buyvm.net) I do have a
[referral link](https://my.frantech.ca/aff.php?aff=3783) if you want them to kick me a few dollars for your
purchase. [Hetzner](https://www.hetzner.com/cloud) (referral: `ckGrk4J45WdN`) or [netcup](https://www.netcup.eu/) (referral:
`36nc15758387844`) would also be very good options; I've used them all and
am very comfortable recommending them.
### Creating a Certificate Authority {#creating-a-certificate-authority}
After picking a device with a static IP address, it needs to be set up
as a lighthouse. This is done by first creating a Certificate Authority
(CA) that will be used for signing keys and certificates that allow our
other devices into the network. The `.key` file produced by the following
command is incredibly sensitive; with it, anyone can authorise a new
device and give it access to your network. Store it in a safe,
preferably encrypted location.
```bash
nebula-cert ca -name "nebula.example.com"
```
I'll explain why we used a Fully-Qualified Domain Name (FQDN) as the
CA's name in a later section. If you have your own domain, feel free to
use that instead; it doesn't really matter what domain is used as long
### Creating a config file {#creating-a-config-file}
The next step is creating our lighthouse's config file. The reference
config can be found in [Nebula's repo.](https://github.com/slackhq/nebula/blob/master/examples/config.yml) We only need to change a few of
the lines for the lighthouse to work properly. If I don't mention a
specific section here, I've left the default values.
The section below is where we'll define certificates and keys. `ca.crt`
will remain `ca.crt` when we copy it over but I like to leave the node's
cert and key files named as they were when generated; this makes it easy
to identify nodes by their configs. Once we copy everything over to the
server, we'll add the proper paths to the `cert` and `key` fields.
```yaml
pki:
ca: /etc/nebula/ca.crt
cert: /etc/nebula/
key: /etc/nebula/
```
The next section is for identifying and mapping your lighthouses. This
needs to be present in _all_ of the configs on _all_ nodes, otherwise they
won't know how to reach the lighthouses and will never actually join the
network. Make sure you replace `XX.XX.XX.XX` with whatever your VPS's
public IP address is. If you've used a different private network range,
those changes need to be reflected here as well.
```yaml
static_host_map:
"192.168.100.1": ["XX.XX.XX.XX:4242"]
```
Below, we're specifying how the node should behave. It is a lighthouse,
it should answer DNS requests, the DNS server should listen on all
interfaces on port 53, it sends its IP address to lighthouses every 60
seconds (this option doesn't actually have any effect when `am_lighthouse`
is set to `true` though), and this lighthouse should not send reports to
other lighthouses. The bit about DNS will be discussed later.
```yaml
lighthouse:
am_lighthouse: true
serve_dns: true
dns:
host: 0.0.0.0
port: 53
interval: 60
hosts:
```
The next bit is about [hole punching](https://en.wikipedia.org/wiki/Hole_punching_%28networking%29), also called _NAT punching_, _NAT
busting_, and a few other variations. Make sure you read the comments for
better explanations than I'll give here. `punch: true` enables hole
punching. I also like to enable `respond` just in case nodes are on
particularly troublesome networks; because we're using this as a support
system, we have no idea what networks our nodes will actually be
connected to. We want to make sure devices are available no matter where
they are.
```yaml
punchy:
punch: true
respond: true
delay: 1s
```
`cipher` is a big one. The value _must_ be identical on _all_ nodes _and_
lighthouses. `chachapoly` is more compatible so it's used by default. The
devices _I_ want to connect to are all x86 Linux, so I can switch to `aes`
and benefit from [a small performance boost.](https://www.reddit.com/r/networking/comments/iksyuu/comment/g3ra5cv/?utm_source=share&utm_medium=web2x&context=3) Unless you know _for sure_
that you won't need to work with _anything_ else, I recommend leaving it
set to `chachapoly`.
```yaml
cipher: chachapoly
```
The last bit I modify is the firewall section. I leave most everything
default but _remove_ the bits after `port: 443`. I don't _need_ the `laptop` and
`home` groups (groups will be explained later) to access port `443` on this
node, so I shouldn't include the statement. If you have different needs,
take a look at the comment explaining how the firewall portion works and
make those changes.
Again, I _remove_ the following bit from the config.
```yaml
- port: 443
proto: tcp
groups:
- laptop
- home
```
### Setting the lighthouse up {#setting-the-lighthouse-up}
We've got the config, the certificates, and the keys. Now we're ready to
actually set it up. After SSHing into the server, grab the [latest
release of Nebula for your platform,](https://github.com/slackhq/nebula/releases/latest) unpack it, make the `nebula` binary
executable, then move it to `/usr/local/bin` (or some other location