VPS security · Practical guide

Build and test a VPS firewall policy without breaking SSH or IPv6

Inventory listeners, coordinate the provider firewall with UFW, preserve administration access and verify allowed and blocked services externally.

Archive placement: April 2023

Network equipment in server racks

A firewall policy should describe the services a VPS is supposed to expose. Starting with a list of familiar port numbers often misses an administration port, IPv6 listener or container-published service. This guide begins with the actual workload, then builds and tests a policy with a recovery path available.

Create a listener and dependency inventory

Read-only listener inspection
sudo ss -lntup
ip -brief address
sudo ufw status verbose
grep '^IPV6=' /etc/default/ufw

For each listener, record its process, protocol, bind address, intended audience and required source networks. A service bound to 127.0.0.1 is different from the same service bound to 0.0.0.0 or ::. Decide whether databases should be local-only, restricted to application servers or intentionally public; a firewall does not justify an unnecessarily broad application bind address.

Include outgoing dependencies such as DNS, package repositories, certificate validation and an external mail provider. If you use containers, review their networking and firewall integration separately. Published container ports do not always follow the same path as an ordinary host service protected by UFW.

Coordinate the provider and guest firewall layers

Plenty Host's built-in firewall controls traffic at the VPS network layer. UFW or another guest firewall controls traffic inside the operating system. Both must permit a connection for it to work. Provider-managed restrictions, including SMTP policy, are independent of customer allow rules.

In the Control Panel, review inbound and outbound defaults, rule order, enabled state and the applied/pending indicator. Name rules by purpose so that an administration exception is distinguishable from a customer-facing service. Do not pause all customer rules merely to avoid understanding which layer blocked a connection.

Preserve administration before enabling a new host policy

The following starting policy permits the example SSH, HTTP and HTTPS services. It is suitable only after confirming those are the intended ports and checking the existing firewall. It does not reset a firewall that already has meaningful rules.

Example host policy for the stated workload
sudo ufw allow 22/tcp comment 'SSH administration'
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw show added

Review the pending rule set before running sudo ufw enable. Keep the old SSH session open and test a new one immediately after enabling. For a nonstandard SSH port, add the actual port first. If you administer over a fixed network, you can later replace the broad SSH allowance with an appropriate source-restricted rule after verifying it.

Restrict administration deliberately

Example source-restricted rule: replace the documentation address
sudo ufw --dry-run allow proto tcp \
  from 203.0.113.10/32 to any port 22
sudo ufw status numbered

The address above is reserved for documentation and will not permit your real workstation. Replace it with the actual administration address or network and review the dry run. Add the real rule, test a separate login from an allowed source, and only then remove the earlier broad allowance. Use the current numbered list or an exact rule expression when deleting; numbers change after deletions.

For IPv6, decide which administration sources should be allowed and test them explicitly. Turning off IPv6 in UFW does not establish that IPv6 traffic is blocked elsewhere. Review the service's IPv6 bind address, provider rules and guest policy as one connection path.

Verify both successful and refused paths

From a separate machine on a network you control
ssh -o ConnectTimeout=8 vpsuser@server.example.com
curl --connect-timeout 8 --max-time 15 -I https://example.com/
nc -vz -w 5 server.example.com 3306

The intended result for port 3306 depends on your design: for a local-only database, a remote connection should not succeed. A timeout can indicate filtering; an immediate refusal can indicate a closed listener or a reject rule. Neither proves that the application is healthy, so verify allowed services at the protocol level as well.

Repeat relevant tests over IPv4 and IPv6 and, where possible, from an unauthorized source. A successful test from your already-allowed office does not establish that the rest of the Internet is blocked. Restrict testing to systems you own or are authorized to administer.

Document recovery and monitor changes

Save the intended rule set and its purpose alongside the service inventory. UFW status and the Control Panel's export function can support that record, but exports are not substitutes for understanding provider protections and application bind addresses. Check the effective result after adding an IP, changing an application port or moving a workload.

  • Confirm a working console and a second administrative login before restrictive changes.
  • Check applied status rather than assuming saved provider rules are already active.
  • Keep database and management ports private unless a documented use requires otherwise.
  • Review logs and rule counts after testing; avoid permanent noisy logging on busy rules.

Primary documentation

← Back to all guidesDiscuss your hosting setup ↗