Introduction
Self Hosting at home is definitely interesting. You can use your hardware without having to pay any fees to a company. You can also usually get a much better hardware, and you don't need to comply with any stupid TOS. Recently, I replaced most of my online VPS'ses with my server. In today's post, I'll show you my journey into self-hosting at home, and I'll share all the tricks that I learned so far. This guide will also not include any software like Cloudflare tunnel or Ngrok. We will use a old school way that just works.
Why hosting at home?
The truth is that even using cheap providers like RackNerd and Cloudcone, paying a good VPS is expensive, specially when you want to self-host heavier pieces of software. I spent about $150 creating my home server. The hardware I've is nearly the same as a bare-metal server that would cost about $110/month! With this hardware, I can self-host anything, no matter how heavy is the software.
I'm also able to safely store sensitive data since I'm 100% sure that no data is being sold behind my back.
The downsides of Self Hosting at home
The major issue of self-hosting at home is energy and internet. With VPS, your server is located in a datacenter with a blazing fast internet and a somewhat stable energy.
At home, you have your energy and connection. Customers are less priority compared to business when it comes to energy and connection, so your projects may go down for more time.
How I do it
The way I do it (and the way I recommend doing it for now) is using an SSH tunnel. SSH tunnels are easy to set and understand. They allow you to expose a local port to a remote ssh connection. In this case, we will expose the connection to a remote VPS. The heavy lifting is all made on the local server, the VPS is just redirecting the internet access to your VPS, so the VPS really does not need many resources. You are welcome to get that 1 core with 512MB of ram VPS. Make sure the VPS has a great connection though and that it has the desired latency for you. If you are hosting games, you will want a VPS from your country.
The initial setup
The first thing I recommend doing is creating a folder on /etc for your tunnels. You can do it at your local machine.
mkdir /etc/sshtunnels
Now, inside this folder, you can create the tunnels that you want. For example, let's say you want to expose Jellyfin. You can create a file with a proper name, e.g:
touch /etc/sshtunnels/jellyfin_tunnel.txt
Inside the file, you can choose the local port to expose and the remote port that will receive the connection
nano /etc/sshtunnels/jellyfin_tunnel.txt
# Now inside the file, add:
8096:8096
The first number is the local port. By default, Jellyfin runs on 8096, so you can select it to expose. For the remote port, you can choose any port. I recommend keeping the same port as that is easier to remember.
Now, you can create a bash service that will be the responsible for managing the tunnels:
nano -w /usr/local/bin/sshtunnel.sh
You can copy this text now.
Make sure to replace "YOURVPSUSER" and "YOURVPSIPHERE" with the actual user and ip. You also need to specify a ssh key that have access to the remote access. If you need any clarification about it, feel free to comment here and I will help you.
You can also decide a specific port instead of using the default port 22. This helps to prevent attacks on the remote VPS.
#!/bin/bash
REMOTE_USER="YOURVPSUSER"
REMOTE_HOST="YOURVPSIPHERE"
SSH_KEY="/home/aquasp/.ssh/id_ed25519"
INSTANCE="$1"
CONFIG_FILE="/etc/sshtunnels/${INSTANCE}.txt"
PORT="22"
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "Config file $CONFIG_FILE not found"
exit 1
fi
FORWARD_OPTS=""
while IFS=: read -r local_port remote_port; do
[[ -z "$local_port" || -z "$remote_port" ]] && continue
# Check if remote port is in use and kill it
ssh -p "$PORT" "$REMOTE_USER@$REMOTE_HOST" "lsof -i :$remote_port -t | xargs -r kill -9"
FORWARD_OPTS="$FORWARD_OPTS -R $remote_port:localhost:$local_port"
done < "$CONFIG_FILE"
if [[ -z "$FORWARD_OPTS" ]]; then
echo "No valid tunnel configurations found in $CONFIG_FILE"
exit 1
fi
exec /usr/bin/ssh -o StrictHostKeyChecking=no \
-o GatewayPorts=yes \
-o ServerAliveInterval=60 \
-o ExitOnForwardFailure=yes \
-N \
-i "$SSH_KEY" \
-p "$PORT" \
$FORWARD_OPTS \
"$REMOTE_USER@$REMOTE_HOST"
Now, you can finally change the file permissions for the script:
chmod +x /usr/local/bin/sshtunnel.sh
For the systemd service, you can do the following:
nano -w /etc/systemd/system/sshtunnel@.service
And then copy the following:
[Unit]
Description=SSH Tunnel Service for %i
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/sshtunnel.sh %i
Restart=always
RestartSec=15
User=aquasp
Group=aquasp
WorkingDirectory=/home/aquasp
Type=simple
TimeoutStartSec=30
[Install]
WantedBy=multi-user.target
Now, make sure to reload SystemD and start the required services:
systemctl daemon-reload
Now, to start the service, you can run the following code (adapt to the actual name of the TXT you created before. In this guide, we used jellyfin_tunnel.txt):
sudo systemctl enable sshtunnel@jellyfin_tunnel.service
sudo systemctl start sshtunnel@jellyfin_tunnel.service
Finally, check the status and check if your connection is up:
sudo systemctl status sshtunnel@jellyfin_tunnel.service
If everything looks great, it will be looking like this:

Conclusion
That is it. You now have an way to put your projects and softwares live on the internet without opening your local network ports. This works under any CGNAT setup.
If you enjoyed this article, you can share it with your friends or subscribe to The Self Hosting Art. Thank you for reading :)
You can also help with XMR(Monero):

8AWKRGyqQ6fdaLwGVAdVTbEP6ZttSXwcYWQWy7gnq6zceTngtJgaAr82Hxr2FY5bkCUJVerccH9XNFX1qWnZxuGYTU5bJ34