· 3 min read
#025

Run ngrok as a systemd Service for PostgreSQL Database

ngrok systemd linux tunneling

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.

If you enjoyed this post, consider subscribing.
Get my next post delivered to you.

All articles