Port Forwarding: Reach Any Server Service From Your Own Machine
The Port Forwarding tab tunnels a service on your server to a port on your own machine, over the SSH connection you already have. Build local, remote, or dynamic SOCKS forwards from a form, test one before you save it, and start or stop it in a click. Nothing is ever exposed to the internet.
The database is on a private network. The Grafana dashboard never leaves the VPC. The staging app answers on 127.0.0.1 and nothing else. That is all correct, and it is exactly how those things should be configured. It is also why reaching any of them from your own laptop usually turns into one of three bad answers: open a port to the internet, edit firewall rules you will forget to revert, or stand up a VPN for one afternoon's work.
There has always been a fourth answer. An SSH tunnel borrows a port number on your computer and pipes it, over the connection you already have, to something running on the server. Nothing is published, nothing changes on the server, and the access disappears when you disconnect. The catch was never the idea. It was that the tunnel lived in a command you retyped, in a terminal window you had to leave open. The Port Forwarding tab makes it a saved, named thing you start with one click, using the same connection and the same SSH key you already set up. For a shorter overview of what the SSH tunnel manager is for before you set one up, see the feature page.
What you can do in the Port Forwarding tab
- Reach a service behind the server's firewall as if it were running on your own machine.
- Share something running on your machine with the server's network, without a deploy or a public URL.
- Route your whole browser through the server with a SOCKS proxy.
- Save a forward with a name and a group, so you stop retyping it.
- Read the real
sshcommand CtrlOps will run, before you commit to it. - Test the connection and find out it works before you save it.
- Paste a command you already have and turn it into a saved forward.
- Start and stop any forward with one click, with no terminal window to babysit.
- Start the forwards you use daily automatically when CtrlOps opens.
- Filter, group, and count forwards across every server you connect to.
- Copy a forward's command back out whenever you need it somewhere else.
Why a Port Forwarding tab instead of ssh -L
| Doing it by hand | Doing it in CtrlOps |
|---|---|
Recall whether it is -L, -R, or -D for what you are actually trying to do | Pick one of three cards that describe the outcome, not the flag |
Get the order right in -L 8080:127.0.0.1:80, and remember which side is which | Fill in Listen on and Remote host, labelled from and to |
| Retype the command, or dig through shell history, every single time | Save it once under a name like Payments database |
| Remember which port PostgreSQL, Redis, or MongoDB listens on | Click a Common services chip and the ports fill themselves in |
| Keep a terminal window open for the whole life of the tunnel | Click Start, and there is no window to babysit |
Remember -N so SSH does not hand you a shell you did not ask for | CtrlOps writes the whole command, -N included, and shows it to you |
| Point a client at it and find out from a timeout whether it worked | Click Test connection and read the answer before you save |
Track what is running with ps and lsof -i | The header chip counts what is active, and on how many servers |
| Find and kill the right process to close a tunnel | Click Stop on the row |
| Nothing groups a dozen tunnels across four different servers | Forwards are grouped, searchable, and counted per group |
| Re-open every tunnel by hand after a reboot | Tick Start automatically when CtrlOps opens |
| Paste a colleague's command into a note and hope to find it again | Click Import, paste it once, and it becomes a saved forward |
Before you start
You need very little, and none of it is on the server.
| Requirement | Why you need it | What to do if it is missing |
|---|---|---|
| An active server connection | The tunnel runs inside the SSH connection you already have | Open the server from the Home page first |
| A service listening on the server | A forward carries traffic to something, it does not start anything | Confirm the process is running from the PM2 tab or the AI Terminal |
| A free port on your own machine | The forward borrows a local port number to listen on | Pick a different Listen on port if the one you want is taken |
A forward changes nothing on the server. No firewall rule, no sshd_config edit, no public port, nothing to undo afterwards. If you can SSH to the box today, you can forward today.
Open the Port Forwarding tab
Connect to your server
Open CtrlOps and click the server you want to tunnel into. Wait for the header to show Connected, because the forward runs inside that connection.
Click the Port Forwarding tab
In the left sidebar, click Port Forwarding. It sits at the bottom of the list, below Cron Jobs.
Read the empty state
With nothing saved yet, the tab explains itself rather than showing you a blank list. A diagram traces the path the traffic actually takes, and three cards name the reasons people reach for this: opening a production database in your own SQL client, seeing an internal dashboard that never leaves the private network, and skipping the VPN entirely.
The chip beside the heading counts how many forwards are running and across how many servers, so a glance tells you whether anything is currently up.
Create a port forward
Click Forward
Click the green Forward button (top right of the Port Forwarding tab)
A two-step panel opens on Step 1 of 2, headed What do you want to reach?
Choose what you want to reach
Three choices, each with a diagram that animates the path the traffic takes. Pick by outcome, not by flag. See the three kinds of forward below for what each one is actually for, then click Continue.
Name the forward and group it
Give it a name you will recognise in a list of twenty, like Payments database. Group is optional and only organises the list, for example Database.
Set the ports
Listen on is what opens on your machine. Remote host is what the tunnel connects to on the other side. The form labels them from and to for exactly that reason. See filling in the form for what goes in each field.
Test the connection, then save
Click Test connection, then Save forward
A success means the tunnel opened and something answered on the far side. The forward joins the list, under the group you gave it.
Two save buttons sit side by side. Save forward adds it to the list without starting it, which is what you want when you are setting several up at once. Save & start does both, and is the one to use when you are about to reach for the thing right now.
The three kinds of forward
| Choice | What it does | Reach for it when |
|---|---|---|
| Reach something (Local) | Opens a port on your machine that reaches a service the server can see | The production database or an internal dashboard is behind the server's firewall |
| Share something (Remote) | Opens a port on the server's network that reaches something on your machine | A teammate needs to see the app on your laptop, or a webhook has to arrive locally |
| Browse through (Dynamic) | Starts a SOCKS5 proxy that routes your browser through the server | An admin panel only accepts connections from inside the network |
Reach something behind the server's firewall
The common case, and the one most people come here for. A service is running on the server and bound to its own loopback address, so nothing outside can reach it. A local forward opens that port on your machine instead, and everything you point at it travels inside the SSH connection.
This is how you open a production database in TablePlus, DBeaver, pgAdmin, or MySQL Workbench, and how you view an internal dashboard in your normal browser. The client never has to know SSH is involved.
localhost in Remote host means the server, not your machine. It is read from the far end of the tunnel. This is the single most common way a forward is built backwards.
A forward carries traffic to something, it does not start anything. If the thing on the other end is a Node process, the PM2 tab is where you confirm it is actually running.
Share something running on your machine
The reverse direction. A port opens on the server's network and pipes back to something on your machine, with no deploy and no public URL. Use it to show a teammate the app running on your laptop, or to receive a webhook locally while you are still building the handler for it.
A remote forward is for showing someone the thing before it is real. When the answer is to ship it properly instead, that is what Deployment is for.
Browse through the server
A dynamic forward starts a SOCKS5 proxy on your machine and routes your browser's traffic through the server, so everything you open behaves as if you were sitting on it. Internal hostnames such as admin.internal, wiki.internal, and grafana.internal resolve and load, because the request genuinely arrives from inside the network.
This is the one to pick when the thing you need is not a single port but a whole internal site, or an admin panel that checks where the connection came from.
Fill in the forward form
| Field | What to enter |
|---|---|
| Name | Something you will recognise in an alert or a long list, like Payments database |
| Group | Optional. A label like Database that buckets related forwards together |
| Server the tunnel runs over | Locked to the server you are connected to, so a forward can never point at the wrong box |
| Listen on | The host and port on your machine. 127.0.0.1 and a free port |
| Remote host | The host and port on the other side, as the server sees them |
Common services
Rather than looking up which port a database listens on, click a chip: MySQL, PostgreSQL, MongoDB, Redis, HTTP dev, or HTTPS. The standard ports fill themselves in and you adjust from there.
The command preview
The CMD box shows the real command CtrlOps will run, updating as you type, with a Copy button beside it:
ssh -L 8080:127.0.0.1:80 -N ubuntu@43.205.15.177The command preview is the fastest way to catch a swapped Listen on and Remote host. If the two numbers read backwards in the command, they are backwards in the form.
If you would rather understand the syntax itself, our free SSH tunnel generator builds and explains a local, remote, or SOCKS command flag by flag.
Test the connection before you save
Test connection opens the tunnel and checks that the far side answers on the port you gave, then tells you whether it worked. It is the difference between saving a forward you know works and finding out from a database client timing out ten minutes later.
A failure almost always means one of three things: the service is not running on the server, it is listening on a different port than the one you entered, or the direction is wrong and you actually wanted Share something rather than Reach something.
A green result means the tunnel reached the port. It does not promise the application behind that port is healthy. If the tunnel tests green but the page will not load, the problem is on the far side, not in the forward.
Import an existing ssh command
Most teams already have the tunnel. It lives in three people's shell history and one stale wiki page, and everyone retypes it slightly differently. Import takes that command and turns it into something with a name.
Click Import in the toolbar and paste the whole command:
ssh -L 3001:localhost:5252 ubuntu@203.0.113.10CtrlOps reads the forwarding flag, the local port, the remote host and port, and the user and host it connects as, then saves it as a forward with the same name, group, start, and stop controls as one you built by hand.
Import once, then delete the note the command was living in. A forward you can see in a list is a forward somebody new can find.
Start, stop, and manage a forward
Find the forward in the list
Each row shows the name, the server the tunnel runs over, the port mapping (for example 3001 to localhost:5252), and a badge for the forwarding type. Use Filter forwards to narrow a long list, and the toggle to switch between grid and list views.
Click Start
Click Start on the row
The tunnel opens inside your existing SSH connection and the counter in the panel header updates to show it is active.
Use it, then click Stop
Point your browser or your client at the local port while it runs. Stop closes the tunnel immediately and releases the port on your machine.
Every row carries the same set of actions:
| Action | Where it is | What it does |
|---|---|---|
| Start | Play icon on the row | Opens the tunnel. Becomes Stop while it is running |
| Stop | The same button, once running | Closes the tunnel and releases the local port |
| Copy | Copy icon on the row | Copies the forward's ssh command to your clipboard |
| More | The ... menu | The rest of the per-forward actions, including edit |
| Delete | Trash icon on the row | Removes the saved forward entirely |
Delete removes the saved forward, not just the running tunnel. If you only want it to stop for now, click Stop, which keeps the name, the group, and the ports for next time.
Group your forwards
The optional Group field buckets rows together, and anything without one lands under Ungrouped. Each group header carries its own active count, so a header reading 0/3 active answers "is staging up?" without opening anything.
See it work end to end
The clearest way to understand a forward is to watch one carry real traffic.
A Hello World Node app is running on the server, listening on port 5252. It is not reachable from anywhere else, and no firewall rule is going to change that. Create a local forward with Listen on set to 3001 and Remote host set to localhost:5252, test it, save it, and click Start.
Now open http://localhost:3001 in your browser. The Hello World page loads, and it is being served from the server, not from your machine. Click Stop, refresh the same address, and there is nothing there.
That is the whole idea. Access was something you turned on for as long as you needed it, not something you configured and then had to remember to undo.
Start a forward automatically when CtrlOps opens
Tick Start automatically when CtrlOps opens in the forward's form and the tunnel comes up on its own. It is the right setting for the tunnels you use every day, such as the staging database your SQL client is already pointed at, so the port is already there before you go looking for it.
The forwards worth auto-starting are the three you open every morning. The one-off you opened to debug something at 2am is not one of them, and leaving it on the list is how you end up wondering what is holding port 8080.
What a port forward exposes, and what it does not
Worth understanding, because it explains most of the behaviour on this page.
A forward borrows a port number on your computer and pipes it, over the SSH connection you already have, to something running on the server. The port that opens is on your machine, bound to 127.0.0.1, so only your computer can reach it. The server publishes nothing new. Anyone without your SSH key sees exactly what they saw before, which is a closed port.
Three things follow from that. The tunnel is only as available as the SSH connection underneath it, so if the connection drops, the forward goes with it. Stopping a forward genuinely removes the access, rather than leaving a rule behind that somebody has to remember to clean up. And binding a listener wider than loopback is the one choice that actually changes the risk, which is a server-side decision covered in SSH and Security.
Tips
Name the forward for the thing on the other end, not for the port. Payments database survives a port change. 5432 does not.
Start using Group as soon as you have more than about five forwards. Grouping is what turns a list into something you can read at a glance.
A forward is often the better answer to "can you give me access to the database". It is per person, it needs their own SSH key, and it disappears when they disconnect. Who holds a key is managed in SSH Management, and across a whole fleet in Access Management.
Troubleshooting
Frequently Asked Questions
How do I access a remote database from my local machine over SSH?
Connect to the server in CtrlOps, open the Port Forwarding tab, and click Forward. Choose Reach something (Local), then set Listen on to a free port on your machine and Remote host to the address and port the database listens on, for example 127.0.0.1 and 5432. Click Test connection, save the forward, and start it. Your SQL client now connects to localhost on the port you chose, and the traffic travels inside the SSH connection.
Do I need to open a port on my server's firewall to use port forwarding?
No, and that is the point of it. A forward travels inside the SSH connection you already have, so the database or dashboard keeps listening only on the server's own loopback address. There is no new firewall rule, no public port, and nothing for a scanner on the internet to find.
What is the difference between local, remote, and dynamic port forwarding?
Local brings something on the server to your machine, so you reach a service behind the server's firewall as if it ran locally. Remote does the opposite and publishes something running on your machine to the server's network, with no deploy and no public URL. Dynamic starts a SOCKS5 proxy, so your whole browser behaves as if it were sitting on the server. CtrlOps labels the three Reach something, Share something, and Browse through, so you pick by outcome rather than by flag.
Can I use my own SQL client with a forwarded port?
Yes, that is the usual reason to create one. Once the forward is running, tools like TablePlus, DBeaver, pgAdmin, or MySQL Workbench connect to 127.0.0.1 on the port you chose, exactly as if the database were installed on your machine. The client does not need to know anything about SSH, because CtrlOps is holding the tunnel open.
How do I know an SSH tunnel is working before I rely on it?
Click Test connection in the forward's form before you save it. CtrlOps opens the tunnel, checks that something is actually listening on the far side, and tells you whether it succeeded. A failure almost always means the service is not running on the server, or it is listening on a different port than the one you entered.
What happens to my port forwards when I disconnect or close CtrlOps?
The tunnel closes with the connection. A forward is a channel inside your SSH session, not a change to the server, so nothing is left listening and nothing has to be cleaned up. Your saved forwards stay in the list, ready to start again next time.
Can a port forward start automatically when CtrlOps opens?
Yes. Tick Start automatically when CtrlOps opens in the forward's form. It is the right setting for a tunnel you use every day, such as the database your SQL client is already configured to reach on localhost, so the port is there before you go looking for it.
I already have an ssh -L command, can I import it?
Yes. Click Import in the Port Forwarding toolbar and paste the command, for example ssh -L 3001:localhost:5252 ubuntu@203.0.113.10. CtrlOps parses the flag, the ports, the remote host, and the destination, and turns it into a saved forward you can name, group, and start from the list.
Why does CtrlOps say the port is already in use on my machine?
Something else on your computer is listening on the port you picked for Listen on. Another forward, a dev server, or a database installed locally are the usual culprits. Pick a different local port, such as 3307 instead of 3306, and point your client at that instead. The port on the server does not change.
Is anything exposed to the internet when I create a port forward?
No. The forwarded port opens on your own machine, bound to 127.0.0.1 by default, so only your computer can reach it. The server publishes nothing new. Anyone without your SSH key sees exactly what they saw before, which is a closed port.
Can other people on the server's network reach my remote forward?
By default a remote forward binds to the server's loopback address, so only the server itself can reach it. Letting other machines on that network connect requires GatewayPorts to be enabled in the server's sshd_config, which is a server-side setting rather than something CtrlOps can turn on for you.
Do I still need a VPN if I use port forwarding?
For reaching a specific service, no. A forward gives you the one port you actually need, over a connection you already trust, with no client to install and no network-wide access to grant. A VPN is still the right tool when you need broad access to a whole network for a whole team, rather than one service for one person.
Cron Jobs
The Cron Jobs tab schedules work on your server without cron syntax. Pick a frequency from a dropdown, point the job at a shell command, a saved script, or a URL, and get a Slack, Telegram, or webhook alert the moment a run fails. Every run is logged with its full output.
Server Management
Add, connect, and manage Linux servers from the CtrlOps dashboard. Quick-connect via SSH string, set up keys, and back up your server list.