Skip to content
Work
MEDIUMDevOps / networking and secure remote access01/2025–present

Reverse proxy and SSH tunnel

nginxautosshOpenSSHsupervisordDockerTLS terminationVPS
github.com/itd24/reverse-proxy

Overview

This is how my home server becomes reachable from the internet without opening a port at home. My connection is a consumer line, so the public entry point is a small VPS.

One container holds nginx and autossh. Autossh opens a reverse tunnel to the VPS. Traffic that arrives there travels back through the tunnel, and nginx sends it to the right service by host name.

I left TLS out of the container on purpose. The VPS ends the encryption, because that machine is the one that is actually reachable, and it keeps certificates and renewals in one place.

Problem

I wanted to reach my home server from the internet, but my connection is a normal consumer line and I did not want to open a single port at home. I needed one public entry point that sends traffic to the right service.

Approach

  • I used a small VPS as the public entry point.
  • I packed nginx and autossh into one container. It opens an SSH reverse tunnel from my home network to the VPS.
  • I let nginx route traffic by host name to the right service on the Docker network.
  • I used supervisord to keep both processes running.
  • I left TLS out of this container on purpose.
  • I wrote the setup order into the README: generate the key, authorise it on the tunnel server and point autossh at the right host and port.

Architecture and design decisions

  • The tunnel is a reverse tunnel from home to the VPS. Traffic that arrives at the VPS on port 8901 travels back through the tunnel into the container.
  • Inside the container, nginx sends each host name to its service: the NestJS API, Dashy, Firefly III, Paperless, Grocy, Mealie and n8n.
  • Jellyfin is reached through host.docker.internal, because it runs directly on the host and not in a container.
  • The image is nginx plus autossh and supervisor. All server blocks live in one default.conf, which is mounted over the stock config.
  • The default server block serves static privacy policy pages.
  • A TLS proxy on the VPS, Caddy or nginx, ends the encryption and forwards to the tunnelled port. Certificates and renewals stay in one place, on the machine that is reachable.
  • The home setup stack builds and starts the container as nginxautossh.

Reliability and performance

  • supervisord watches both processes, so a dropped tunnel comes back on its own and the site does not stay dark.
  • No inbound port is open at home.
  • The private key and known_hosts file are git ignored. The keys folder only holds a README.
  • TLS is handled in one place, so renewals do not touch the home setup.

Outcomes

  • My home services are reachable from the internet with no open port at home.
  • One entry point serves eight internal services by host name.
  • A dropped tunnel recovers without me.
  • Certificates are managed on the VPS only.
  • No key material is stored in version control.

Known gaps

  • I have no numbers on uptime, how often the tunnel drops or how fast it comes back.
  • I do not describe the VPS setup, the TLS proxy configuration or the firewall rules.
  • I have not measured speed through the tunnel.
  • It is built for one household. I do not claim it suits heavy traffic.
  • I do not say which licence the repository uses.

Get in touch

Hiring for architecture, technical leadership or applied AI engineering?

I answer questions about any of the case studies in detail, including the parts the source material does not cover.