
A firewall mistake on a VPS usually fails in one of two ways. You lock yourself out. Or you leave a service exposed for months. This VPS firewall setup guide tutorial uses a staged approach: keep SSH reachable, block what you don’t need, and add a second layer at the provider edge.
The commands below assume Ubuntu 24.04 LTS and Debian 12/13-style layouts. The same workflow applies to most Linux VPS builds.
Whether you run WordPress, a control panel, or a few custom sites, you’ll finish with rules you can explain, audit, and test from the outside.
What you’ll build (and why it’s safer than “just enable UFW”)
You’ll set up three layers that cover different failure modes:
- Host firewall (UFW) so the VPS enforces policy regardless of provider settings.
- Provider cloud firewall (network ACL/security group equivalent) to drop junk traffic before it reaches the VM.
- Verification + rollback steps so an experiment doesn’t turn into downtime.
This matters in real hosting. If a plugin opens a debug listener, or a staging service starts on a random port, the edge firewall can still stop it from being reachable.
Prerequisites before you touch the firewall
- Root or sudo access.
- At least one active SSH session you can keep open during changes.
- Your admin IP(s) (office/home/VPN). If you don’t have a stable IP, use a VPN with fixed egress.
- Know what you’re hosting: web only (80/443), mail (25/587/465/143/993), control panel ports, or app ports.
If basic access is still shaky, harden SSH first. Then come back to the firewall.
For a safe sequence that avoids lockouts, follow the SSH lockdown tutorial.
Step 1: Inventory what’s listening right now
Before you write rules, confirm what the server is actually exposing. Run:
sudo ss -tulpn
sudo ss -tulpn | awk 'NR==1 || /LISTEN/'
Typical ports you should be able to identify:
:22SSH:80HTTP and:443HTTPS:3306MySQL (usually localhost-only on a single VPS):2087/:2083cPanel/WHM (if applicable)
Also check what starts automatically at boot:
systemctl list-unit-files --type=service --state=enabled
If you see a port you don’t recognize, pause and investigate.
Disabling an unnecessary service is usually cleaner than hiding it forever behind firewall rules.
Step 2: Set a baseline cloud firewall (edge filtering)
Most VPS providers include a cloud firewall or security rules in the control panel. Set this up early.
This reduces log noise. It also blocks random scanners before they ever touch your VM.
Baseline for a typical web server:
- Allow inbound TCP 22 from your admin IP only.
- Allow inbound TCP 80 and 443 from any.
- Deny all other inbound.
If the same VPS also runs email (common for hosting resellers), you’ll need mail ports too.
If you’re not sure what to open, confirm your stack first. Or follow the VPS email setup tutorial and open only what you’ll actually use.
HostMyCode customers typically keep the edge ruleset small. Then they enforce the detailed policy with UFW on the instance.
If you’re still sizing a server, a HostMyCode VPS gives you the flexibility to run UFW, Fail2Ban, and per-site tuning without shared-host constraints.
Step 3: Install and enable UFW (without cutting off SSH)
On Ubuntu and Debian, UFW is a simple wrapper for managing nftables rules. It also helps you avoid common foot-guns.
sudo apt update
sudo apt install -y ufw
Check your current status:
sudo ufw status verbose
Start with sane defaults. Deny inbound and allow outbound.
sudo ufw default deny incoming
sudo ufw default allow outgoing
Critical: allow SSH before you enable UFW.
If you moved SSH to a non-standard port (recommended), use that port instead of 22.
# If SSH is on 22
sudo ufw allow 22/tcp comment 'SSH'
# If SSH is on 2222
# sudo ufw allow 2222/tcp comment 'SSH'
Then allow web traffic:
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
Enable UFW:
sudo ufw enable
Verify what you actually applied:
sudo ufw status numbered
Step 4: Restrict SSH to your admin IP (and keep a safe fallback)
SSH from anywhere is convenient, but it creates constant noise. It also increases exposure to password-spray attempts.
If you have a stable admin IP, lock SSH down.
First add an allow rule for your IP (replace 203.0.113.10):
sudo ufw allow from 203.0.113.10 to any port 22 proto tcp comment 'SSH admin IP'
Then remove the broad rule that allows SSH from everywhere. Use the numbered list:
sudo ufw status numbered
sudo ufw delete <rule_number_for_SSH_anywhere>
Fallback option: if your IP changes frequently, use a bastion/jump host. Avoid loosening SSH “temporarily.”
Temporary rules tend to stick around. See the SSH jump host setup guide.
Step 5: Add rules for common hosting services (only if you run them)
Don’t copy a huge allowlist from the internet.
Open ports based on what this VPS is responsible for today.
Mail server ports (Postfix/Exim + Dovecot)
If your VPS handles email directly, these are the usual ports:
- SMTP: 25/tcp (server-to-server)
- Submission: 587/tcp (modern client send)
- SMTPS: 465/tcp (legacy but still used by some clients)
- IMAP: 143/tcp (prefer 993)
- IMAPS: 993/tcp
sudo ufw allow 25/tcp comment 'SMTP'
sudo ufw allow 587/tcp comment 'Submission'
sudo ufw allow 465/tcp comment 'SMTPS'
sudo ufw allow 143/tcp comment 'IMAP'
sudo ufw allow 993/tcp comment 'IMAPS'
If deliverability matters, don’t ignore reverse DNS and SPF/DKIM alignment. Those fix many “mail goes to spam” complaints.
Use email deliverability troubleshooting.
cPanel/WHM ports (only for cPanel servers)
On a cPanel VPS, you’ll usually need:
- WHM: 2087/tcp
- cPanel: 2083/tcp
- Webmail: 2096/tcp
Best practice: restrict these ports to your admin IP, not the entire internet.
sudo ufw allow from 203.0.113.10 to any port 2087 proto tcp comment 'WHM admin'
sudo ufw allow from 203.0.113.10 to any port 2083 proto tcp comment 'cPanel admin'
sudo ufw allow from 203.0.113.10 to any port 2096 proto tcp comment 'Webmail admin'
If you want a broader cPanel hardening checklist (services, accounts, and WHM settings), use cPanel hardening alongside this firewall guide.
Allowing inbound for a reverse proxy or load balancer
If you run Nginx in front of Apache or multiple apps, you may only need 80/443 on the public interface.
Keep app ports bound to 127.0.0.1 whenever you can.
Treat the firewall as a backstop, not your only control.
Step 6: Turn on useful firewall logging (and keep it readable)
Logging helps you spot unexpected scans and broken rules. But “full” can get loud on a public IP.
Medium is a good default.
sudo ufw logging medium
Where to look:
- Ubuntu:
/var/log/ufw.log(if enabled) and/var/log/syslog - Debian: typically
/var/log/kern.logor/var/log/syslog
Quick check for recent blocks:
sudo journalctl -k --since "1 hour ago" | grep -i ufw | tail -n 50
If you prefer daily summaries over raw logs, add a reporting tool.
This pairs well with a small VPS: Logwatch setup.
Step 7: Verify from the outside (don’t trust local checks)
ufw status only tells you what the host thinks it applied.
You still need an outside view.
From another machine (not your VPS), test ports with nc:
# Replace vps.example.com or IP
nc -vz vps.example.com 22
nc -vz vps.example.com 80
nc -vz vps.example.com 443
nc -vz vps.example.com 3306
Expected results:
- 22/80/443 should connect (22 only from your admin IP).
- 3306 should fail unless you intentionally exposed it (rare for single-server hosting).
If you’re mid-migration, double-check you’re testing the right IP.
DNS cache issues can look exactly like firewall issues. This workflow keeps cutovers predictable: DNS cutover testing.
Step 8: Common pitfalls (and fast fixes)
You enabled UFW and lost SSH
- If you still have an existing session open, run:
sudo ufw allow 22/tcp(or your SSH port). Then re-test from your client. - If you’re locked out completely, use your provider console/VNC to log in and run:
sudo ufw disable. Then re-apply rules carefully.
Let’s Encrypt renewal fails after firewalling
HTTP-01 challenges require inbound 80/tcp. If you only allow 443, renewals can fail depending on your ACME setup.
- Fix: allow 80/tcp temporarily or permanently if you rely on HTTP-01.
- If you need the full certificate workflow, see the VPS SSL setup guide.
Control panel works on the LAN but not from your office
This is almost always an allowlist mismatch.
- Confirm your current public IP:
curl -4 ifconfig.me - Add that IP to the UFW allow rules for 2087/2083/2096 (or your panel ports).
- Also check the provider cloud firewall; it can block even if UFW allows.
High CPU from logging or bot traffic
UFW isn’t heavy, but kernel logging can be.
If logs spike, drop to “low” and let the edge firewall cut the noise:
sudo ufw logging low
Step 9: A practical ruleset you can copy (web + SSH allowlist)
Here’s a clean starting point for a typical web VPS.
Replace your admin IP and SSH port if needed.
sudo ufw --force reset
sudo ufw default deny incoming
sudo ufw default allow outgoing
# SSH (restrict to admin IP)
sudo ufw allow from 203.0.113.10 to any port 22 proto tcp comment 'SSH admin'
# Web
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
# Optional: rate-limit SSH (helps with noisy scans)
sudo ufw limit 22/tcp comment 'SSH rate limit'
sudo ufw logging medium
sudo ufw enable
sudo ufw status verbose
Note: ufw limit uses recent connection tracking to slow brute-force attempts.
It won’t replace SSH keys and Fail2Ban. But it does cut down the obvious junk.
Step 10: Maintenance checklist (monthly, 10 minutes)
- Confirm listening ports:
ss -tulpn - Review rules:
ufw status numbered - Check blocked spikes: scan
journalctl -kfor repeated UFW blocks - Validate edge firewall still matches UFW intent (ports drift during emergencies)
- Test SSH from your backup admin location (VPN exit, secondary IP, or bastion)
When you should use a managed VPS instead
If your VPS hosts client sites, mail, and a control panel, firewall changes become operational risk.
In that situation, a managed plan can cost less than a single outage.
HostMyCode’s managed VPS hosting fits if you want hardened defaults (firewalling, patch cadence, basic monitoring). It also lets you stay focused on websites and customers instead of incident response.
If you’re building a production server in 2026, pick a VPS that lets you control both edge rules and the host firewall. A HostMyCode VPS gives you the access you need for UFW, SSL, and performance tuning. If you’d rather hand off routine hardening, choose managed VPS hosting and keep every change documented and easy to roll back.
FAQ: VPS firewall setup guide tutorial
Should I use only a cloud firewall or only UFW?
Use both. The cloud firewall drops traffic before it reaches your VPS, and UFW enforces policy even if edge rules drift later. Together, they reduce risk and keep logs quieter.
Do I need to allow port 80 if my site is HTTPS-only?
Usually, yes. Many Let’s Encrypt setups rely on HTTP-01 validation over port 80. You can still redirect traffic to HTTPS while leaving 80 open for validation.
Is it safe to expose cPanel/WHM to the public internet?
It works, but it’s not ideal. Restrict WHM/cPanel ports to your admin IP (or a VPN/bastion) and keep AutoSSL and updates current.
How do I confirm I didn’t accidentally expose a database port?
Run ss -tulpn to see what’s listening. Then test externally with nc -vz your-ip 3306. Also ensure MySQL binds to 127.0.0.1 unless you explicitly need remote access.
What’s the quickest rollback if I break something?
If you still have SSH access, fix the rule and reload UFW. If you’re locked out, use your provider console and run ufw disable. Then re-apply rules step by step.
Summary
A good firewall is boring. It allows exactly what you need, often just SSH from your IP plus 80/443.
It blocks everything else at two layers: edge and host. Start from an inventory, verify externally, and keep a rollback path.
If you’re deploying on a new server, match the plan to your responsibility level. Start with a flexible HostMyCode VPS, or choose managed VPS hosting if you want hardening and ongoing maintenance handled for you.