❖ Introduction
Tilde aims to be a starting point for anyone getting started in their self-hosting journey. It uses Pyinfra to configure a new server and deploy commonly used applications using Docker. Please note that Tilde only targets and supports Debian.

❖ Features
Tilde configures the following things for you:
- A Docker install to easily spin up other services
- A Wireguard tunnel with a user-friendly interface so you can access your services when you're not home.
- Dynamic DNS using DuckDNS so that Wireguard can always connect to your server
- A Nextcloud instance for cloud storage
- A Jellyfin instance for media consumption
- Grafana with Prometheus for server monitoring
- Comes with Node Exporter (System Stats) and cadvisor (Container Stats) pre-configured. Add any dashboard compatible with them.
- A Nginx Proxy Manager Instance for reverse proxy and TLS (Configured by the user)
❖ Requirements
Tilde is meant to be very hands off, but there are still a few things you'll need to do manually to set it up for success.
It's not very complicated, but the instructions are written under the assumption that you're at least slightly comfortable with the unix commandline.
We'll go over configuring the requirements for the following things in this section:
❖ Server Configuration and SSH
❖ Operating System
The target server should be running Debian 12 or above. The Install Images provided by Debian include a Graphical Installer, and a TUI installer as well. Feel free to use whichever one you are more comfortable with.
❖ SSH
If you don't have ssh keys set up, please take a look at the Github Docs on the topic.
Your ssh config should should look something like this:
# ~/.ssh/config
host <homeserver>
HostName <internal-ip-of-server>
user <non-root-user>
host *
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519
note
Replace the values wrapped in <> with the appropriate values for your server
The password authentication can be skipped by adding your public key to your server. You can do so manually
by placing it in the ~/.ssh/authorized_keys
file on your server. Or you can use the following command to do it
for you:
ssh-copy-id <homeserver>
❖ Sudo User
For the sake of security and to generally make our lives easier, we will not be logging into the server as root
.
The Debian Installer should have guided you to create another user. But just in case it didn't, if you're already
logged in as root, you can create a new user by running the following command:
adduser <username>
Once we have another user, we need to give that user sudo
privileges. On Debian, sudo
is not installed by
default. We will run the following commands to install sudo
and give our user the proper permissions.
apt install sudo # Install sudo
usermod -aG sudo <username> # Add sudo permissions for our user
❖ Laptop Configuration (Optional)
If you are using an old laptop as your server, we want to make sure that the laptop does not go to sleep when the lid is closed. We can do so by following the steps below.
Open /etc/systemd/logind.conf
in your preferred text editor
sudo vim /etc/systemd/logind.conf
Uncomment and set the HandleLidSwitch
option to ignore
HandleLidSwitch=ignore
Restart the systemd daemon:
sudo systemctl restart systemd-logind
warning
This will log you out
Taken from ask Ubuntu
❖ Port Forwarding
When accessing our services away from home, we'll be using a Wireguard tunnel to VPN into our home network. For this to work however, we need to set up Port Forwarding.
For some background, Tilde configures Wireguard to run on the default port 51820
.
Let's assume that your Server's internal IP is 192.168.1.30
.
We need to tell our Router to send any outside traffic on port 51820
to 192.168.1.30:51820
.
Setting up port forwarding is different from one Router to another. Please look up how to do so for your Router.
Here are some links to point you in the right direction:
❖ Dynamic DNS
❖ Overview
Unless you pay for a static IP, your ISP is free to change your public IP whenever they want. This is usually not a problem, but it is for us. We need to make sure that Wireguard can find our home's public IP at all times.
This is where Dynamic DNS will come to our rescue.
Tilde uses ZenDNS to periodically update the DNS records. While this guide assumes that DuckDNS will be used, ZenDNS also works with Cloudflare and Namecheap. Please read the docs for ZenDNS to configure what works best for you.
It's worth mentioning that I am the author of ZenDNS as well. I wrote it because updating DNS entries through API calls is actually pretty easy. Other tools always seemed more complicated than they had to be. With that said, that's just my experience. If ZenDNS doesn't work well for you please feel free to switch to a Dynamic DNS client like inadyn or ddclient. You can even write your own!
❖ Example
Assuming you're using DuckDNS:
- Sign up for an account
- Pick a new subdomain on the website and click
add domain
- Copy the
token
from the website as well
Fill out src/tilde/templates/zendns.yaml.j2. It should look something like:
duckdns:
- token: "your-token"
domain: "your-subdomain.duckdns.org"
If you're not using DuckDNS, look at the docs for ZenDNS and replace the contents of src/tilde/templates/zendns.yaml.j2 with configuration for your chosen provider.
❖ Environment Variables
As the final pre-requisite before we deploy, you'll also need to fill out some environment variables in the run script.
# run.sh
export USERNAME=<username>
export HOST=<server-from-your-ssh-config>
export WIREGUARD_PASSWORD=<password-you-want-for-wireguard-ui>
export WIREGUARD_HOST=<your-subdomain.duckdns.org>
# Can be obtained by running `id $user`
export TILDE_UID=<uid-here>
export TILDE_GID=<gid-here>
export TZ=America/New_York
❖ Deployment
After all that work, we are finally ready to deploy!!
Tilde only has one dependency: pyinfra. You can either use uv like I do, or just use a venv and install pyinfra yourself, it's totally up to you!
❖ Using uv
uv sync # Create a virutal environment and install pyinfra
source .venv/bin/activate # Activate the virutal environment
./run.sh # Run tilde on your homeserver
❖ Using a venv
python3 -m venv tilde_venv # Create a venv for tilde
source tilde_venv/bin/activate # Activate the venv
pip3 install pyinfra # Install pyinfra and dotenv
./run.sh # Run tilde on your homeserver
If everything goes as expected, you'll have a shiny new home server complete with all the features mentioned earlier!
The services are available at homeserver-internal-ip:service-port
The mapping for the ports is as follows:
Nginx Proxy Manager: 81
Wireguard: 51821
Grafana: 3000
Jellyfin: 8096
Nextcloud: 8080
❖ Service Configuration
You have your shiny new server! Let's talk a little about the services running on this server. There is not much to say about most of these, just things to keep in mind and some tips!
The services running are as follows:
note
There are other services running, but they are auxiliary to the ones listed above. Run docker ps
to see them.
❖ Nginx Proxy Manager
Nginx Proxy Manager is a fancy frontend for Nginx. I'll be calling it NPM from this point forward, and you can expect to see this abbreviation pop up in self hosting communities as well.
If you own a domain, you can use NPM to set up a reverse proxy for your services.
This way, you can access jellyfin at jellyfin.your-domain.com
instead of 192.168.1.30:8096
.
The first time login credentials for NPM are as follows:
Email: admin@example.com
Password: changeme
You can also use NPM to set up TLS/SSL for your services. This will make your browser stop complaining about an insecure connection and let you access your services over HTTPS.
I won't go over how to do that here, but I will link this incredibly helpful Video by Wolfgang's Channel on the topic.
❖ Wireguard
Tilde uses wg-easy to make Wireguard VPN access easy. The password for the UI will be the one set in the run script. You can add profiles for all of your devices, and access your services from anywhere.
Do note that IP collisions can happen when using Wireguard. This is when your current network's private address space is the same as your home network.
For example, devices in your home network are assigned IP address 192.168.1.0 -> 192.168.1.255
and the same is true of the network you are currently connected to.
If you're at a friend's house, you can ask them to change their private address space to be something like 192.168.2.0 -> 192.168.2.255
.
You can also change yours to accomplish the same thing.
This is an oversimplification of how private address spaces are assigned, but illustrates a common problem that I've run into multiple times.
❖ Grafana
Tilde configures Grafana with Prometheus for server monitoring.
In short, Prometheus scrapes a set of data sources and serves that data through Prometheus Query Language. Grafana then takes that data, and displays them to you in a beautiful UI.
The following Prometheus data sources come pre-configured with Tilde:
- Node Exporter: System Stats
- cadvisor: Container Stats
You can then use pre-made Grafana Dashboards to visualize that data. For example, I like using Node Exporter Full as one of my dashboards. This relies on Node Exporter being set up for Prometheus.
❖ Jellyfin
Not a ton to say about Jellyfin. Jellyfin will act as the central hub for most of your media. Just remember to set up the libraries with the proper path during setup.
TV: /data/tv
Movies: /data/movies
Music: /data/music
Take a look at the Jellyfin Docker Compose Template to understand why that is. And look at the Jellyfin Pyinfra Task to understand where you should put your media for Jellyfin to pick up.
❖ Nextcloud
Tilde sets up a very basic Nextcloud instance. This is not the most performant or feature-complete version of Nextcloud, but it is the easiest for a beginner.
The rabbit hole for Nextcloud goes very deep, take a look at the following to learn more: