# Ports and port forwarding on a server, explained

> Make a service reachable: check what listens and where, open the port, test from outside, use SSH tunnels for admin tools and forward ports with nftables.

Difficulty: Intermediate\
Tested on: Ubuntu 24.04 LTS, Ubuntu 26.04 LTS, Debian 12, Debian 13, Windows Server 2022, Windows 11

A network service is reachable from the internet when two things are true: it **listens** on an address the outside world can reach, and the **firewall** allows its port. This guide checks both, tests from outside, and shows two kinds of forwarding: SSH tunnels to reach private services safely, and server-side port forwarding (DNAT) for virtual machines or containers. Replace `203.0.113.10` with your server's address.

## Before you start

- Your HyperDC server has its own public IPv4 address, so you do not need router-style port forwarding to make a service reachable.
- Know the port your service uses, from its documentation or configuration.

## Step 1: See what listens

**Linux**

```bash
sudo ss -tulpn
```

Each line shows the protocol, the local address and port, and the process. Look at the address:

- `0.0.0.0:8080` or `[::]:8080`: listens on all addresses, reachable from outside if the firewall allows it.
- `127.0.0.1:8080` or `[::1]:8080`: listens on the server only, not reachable from outside.
**Windows**

```powershell
Get-NetTCPConnection -State Listen | Sort-Object LocalPort | Select-Object LocalAddress, LocalPort, OwningProcess
```

`0.0.0.0` and `::` mean all addresses; `127.0.0.1` means the server only.

If the service listens on `127.0.0.1` but should be public, change its bind or listen address in its configuration. If it should stay private, keep it that way and use a tunnel (Step 4).

## Step 2: Allow the port in the firewall

- UFW: `sudo ufw allow 8080/tcp`; see [UFW firewall](/guides/ufw-firewall).
- nftables: add `tcp dport 8080 accept` to the input chain; see [nftables firewall](/guides/nftables-firewall).
- Windows: `New-NetFirewallRule -DisplayName "Allow 8080" -Direction Inbound -Protocol TCP -LocalPort 8080 -Action Allow`; see [Windows Defender Firewall rules](/guides/windows-firewall).

Open only what must be public. Restrict admin ports to your own IP address.

## Step 3: Test from outside

Test from your own computer, not from the server:

**Linux and macOS**

```bash
nc -vz 203.0.113.10 8080
```
**Windows**

```powershell
Test-NetConnection 203.0.113.10 -Port 8080
```

**Verify:** the test reports the port as open (`succeeded` or `TcpTestSucceeded : True`). UDP services cannot be tested this way reliably; use the service's own client instead.

## Step 4: Reach private services with an SSH tunnel

A **local forward** makes a service that listens on the server's `127.0.0.1` available on your computer, through the encrypted SSH connection. For example, a database admin tool on port 8080 of the server:

```bash
ssh -N -L 8080:127.0.0.1:8080 alex@203.0.113.10
```

Keep the command running and open `http://localhost:8080` on your computer. `-N` means no remote command, just the tunnel. To reach a database:

```bash
ssh -N -L 5433:127.0.0.1:5432 alex@203.0.113.10
```

Your database client then connects to `localhost:5433`.

A **remote forward** does the opposite: it makes a port on your computer reachable from the server, for example for a webhook test:

```bash
ssh -N -R 9000:127.0.0.1:3000 alex@203.0.113.10
```

On the server, `127.0.0.1:9000` now reaches port 3000 on your computer.

## Step 5: Forward ports on the server (DNAT)

When you run virtual machines on a VDS or dedicated server, or services in a private network behind the server, the server can forward a public port to an internal address. First enable IPv4 forwarding:

```bash
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-forwarding.conf
sudo sysctl --system
```

Then add a NAT table to `/etc/nftables.conf`. This example forwards public port 8080 to port 80 of an internal machine at `10.0.0.2` and masquerades its outgoing traffic:

```text
table ip nat {
    chain prerouting {
        type nat hook prerouting priority dstnat; policy accept;
        iifname "eth0" tcp dport 8080 dnat to 10.0.0.2:80
    }
    chain postrouting {
        type nat hook postrouting priority srcnat; policy accept;
        oifname "eth0" masquerade
    }
}
```

Replace `eth0` with your public interface (`ip -brief link`). If your filter table drops forwarded traffic (as in our nftables guide), allow it in the forward chain:

```text
ct state established,related accept
iifname "eth0" ip daddr 10.0.0.2 tcp dport 80 accept
```

Check and load with `sudo nft -c -f /etc/nftables.conf` and `sudo nft -f /etc/nftables.conf`, then test from outside as in Step 3.

## Troubleshooting

**Connection refused.** Nothing listens on that port, or it listens on `127.0.0.1` only (Step 1).

**Connection timed out.** The firewall drops the traffic, or your own network blocks outgoing connections to that port (Step 2, then try another network).

**Outgoing connections to port 25 time out.** Outbound port 25 is closed by default on HyperDC VPS. For services bought for a term of 3 months or longer, it is opened on request when you open a support ticket. Until then, send mail through a relay on port 587.

**The SSH tunnel says "Address already in use".** The local port is taken on your computer. Choose another local port, for example `-L 18080:127.0.0.1:8080`.

**DNAT works from outside but not from the server itself.** Packets generated on the server do not pass the prerouting chain. Test from another machine.

## Next steps

- Firewall basics: [UFW firewall](/guides/ufw-firewall) and [nftables firewall](/guides/nftables-firewall).
- Run your own virtual machines: [VDS and nested virtualization](/guides/vds-nested-virtualization).

## Frequently asked questions

### Do I need port forwarding on my HyperDC server?

Usually not. Your server has its own public IPv4 address, so a service that listens on it and is allowed by the firewall is reachable directly. Port forwarding on a home router solves a problem a server does not have.

### What is the difference between 0.0.0.0 and 127.0.0.1?

A service listening on 127.0.0.1 only accepts connections from the server itself. 0.0.0.0 (or :: for IPv6) means all addresses, so it can be reached from outside if the firewall allows it.

### How do I reach a database or admin panel without opening its port?

Use an SSH tunnel: ssh -L forwards a port on your computer through the encrypted SSH connection to the service on the server. Nothing extra is exposed to the internet.

### Which tool shows open ports?

On Linux, ss -tulpn lists listening TCP and UDP sockets with the process. On Windows, Get-NetTCPConnection -State Listen does the same for TCP.

### Why can I connect from the server but not from outside?

The service listens on 127.0.0.1 only, or the firewall blocks the port. Check the bind address first, then the firewall rules.

---

Source: <https://hyperdc.com/guides/networking/ports-and-port-forwarding>\
Updated: 2026-10-09
