Run ngrok as a systemd Service for PostgreSQL Database
I use ngrok to expose local services to the internet. This time, I use it to expose a Postgresql Database. It is the easiest way to do it in my opinion
The problem is ngrok stops when I close the terminal. I wanted it to run like a background daemon, start on boot, and restart itself if my home server was rebooted for whatever reason
Here is how I set it up as a systemd service.
Step 1: Install ngrok
First, add the official repository and install ngrok.
# Install ngrok
sudo apt install ngrok
# Add your auth token (from https://dashboard.ngrok.com/get-started/your-authtoken)
ngrok config add-authtoken <YOUR_AUTHTOKEN>
Step 2: Create a ngrok Config File
Put the tunnel configuration in /etc/ngrok so the service can read it.
sudo mkdir -p /etc/ngrok
sudo tee /etc/ngrok/ngrok.yml <<EOF
version: "2"
authtoken: <YOUR_AUTHTOKEN>
tunnels:
postgres:
proto: tcp
addr: 5432
EOF
Replace postgres, tcp, and 5432 with whatever tunnel name, protocol, and port you need.
Step 3: Create the systemd Service
Now create the unit file.
sudo tee /etc/systemd/system/ngrok.service <<'EOF'
[Unit]
Description=ngrok TCP Tunnel for PostgreSQL
After=network.target docker.service
Wants=docker.service
[Service]
Type=simple
ExecStart=/usr/local/bin/ngrok start --config /etc/ngrok/ngrok.yml postgres
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
If you do not use Docker, remove docker.service from After= and Wants=.
The After= and Wants=docker.service lines mean systemd will wait for Docker to be ready before starting ngrok. Since my Postgres runs inside Docker via docker-compose, ngrok needs Docker up first or the tunnel will start while the database is still down.
The ExecStart line is just the shell command systemd runs to launch ngrok. If you are unsure where your ngrok binary lives, run which ngrok to get the exact path and substitute it for /usr/local/bin/ngrok above.
Now tell systemd to pick up the new unit file, then enable and start the service.
sudo systemctl daemon-reload
sudo systemctl enable ngrok # auto-start on boot
sudo systemctl start ngrok # start now
Step 4: Verify It’s Working
Check that the service is running.
# Check service status
sudo systemctl status ngrok
# Check the tunnel URL
curl -s http://127.0.0.1:4040/api/tunnels | jq -r '.tunnels[0].public_url'
You’ll see something like:
tcp://0.tcp.ngrok.io:12345
That is it. The tunnel now survives reboots and reconnects on its own.
Limitations: The URL Changes on Restart
Every time ngrok restarts, it gets a new public URL and port. If your client connection string is hardcoded to tcp://0.tcp.ngrok.io:12345, it will break the next time the service restarts.
For a stable port, you would need to pay for it.