HackerNews discussed this with many alternative solutions: https://news.ycombinator.com/item?id=24893615
I already have my own domain name: mydomain.com
. I wanted to be able to run some webapps on my Raspberry Pi 4B running
perpetually at home in headless mode (just needs 5W power and wireless internet). I wanted to be able to access these apps from public Internet. Dynamic DNS wasn't an option because my ISP blocks all incoming traffic. ngrok
would work but the free plan is too restrictive.
I bought a cheap 2GB RAM, 20GB disk VM + a 25GB volume on Hetzner for about 4 EUR/month. Hetzner gave me a static IP for it. I haven't purchased a floating IP yet.
I created a subdomain u1.mydomain.com
with its A record pointing to the above static IP address.
Then I created two CNAME records, pointing to the above subdomain: home.mydomain.com
and cloud.mydomain.com
.
I disabled nginx
on the server and installed Caddy instead. These are the contents of my /etc/caddy/Caddyfile
:
{
email [email protected]
}
home.mydomain.com {
# These are reverse-proxied to port 10000+n which are SSH
# tunneled into the raspberrypi at my home
reverse_proxy localhost:10080
}
cloud.mydomain.com {
# These are served locally but with automatic HTTPS
root * /usr/share/caddy
file_server
}
I set GatewayPorts clientspecified
in my /etc/ssh/sshd_config
on the server. This is needed so that the client (RaspberryPi) can specify which ports to enabled reverse tunneling on.
I enabled the Ubuntu firewall on this server and allowed incoming traffic on port 80, and 443. For eg: sudo ufw allow 80
Now, on my Raspberry Pi at home, I created a reverse SSH tunnel to this Hetzner VM with:
ssh -N -T -R 10080:localhost:80 [email protected]
And just like that, my site running on port 80 on the Pi is now accessible at https://home.mydomain.com
.
Once we're done testing, we can add the -f
option so that this tunnel runs in the background. To be able to recreate the tunnel (perhaps via crontab
), I put this in a bash script:
#!/bin/bash
createTunnel() {
/usr/bin/ssh -f -N -T -R 10080:localhost:80 [email protected]
if [[ $? -eq 0 ]]; then
echo Tunnel to Hetzner created successfully
else
echo An error occurred creating a tunnel to hetzner. RC was $?
fi
}
/bin/pidof ssh
if [[ $? -ne 0 ]]; then
echo Creating new tunnel connection
createTunnel
fi
If I run any additional apps on the Pi, I'll need to:
- Create a tunnel (or modify the port range for the current one).
- Modify the
Caddyfile
on server and restart caddy withsudo systemctl restart caddy
Future explorations:
- Get
Caddy
or perhapsTCPProxy
to access other services on Pi, not just webapps - Map an entire port range so that the above two steps are not needed everytime I add a new Webapp on the Pi
- Test for IPv6 handling throughtout the stack
Talk to me on Twitter for issues/suggestions.
I saw you were reaching out for suggestions, a simpler and more self-contained approach is to use inlets which has built-in TLS and TCP support for tunnelling services. Quick-start: Tunnel a private SSH server over inlets PRO
Not free, but fairly low price for personal use, and can be used with K8s also.