
A UFW ruleset can look “correct” and still break a server. One badly placed deny can lock you out of SSH. It can also stop Let’s Encrypt validation or make mail clients hang on port 587.
This UFW firewall troubleshooting tutorial gives you a safe, repeatable workflow for Ubuntu 22.04/24.04 VPS and dedicated servers in 2026. First, capture the symptom and confirm what’s listening. Next, prove whether UFW is dropping traffic. Then fix the smallest possible rule. You can do all of this without turning your firewall into Swiss cheese.
Before you touch UFW: avoid lockouts (two-minute safety net)
On a remote server, assume any firewall change could kill your session. Do these two things first:
- Open a second SSH session and leave it idle as a fallback.
- Confirm you have console access (VNC/serial/IPMI). If you’re hosting with HostMyCode, choose a plan that gives you reliable control and predictable networking so recovery is straightforward: HostMyCode VPS.
Optional (but usually worth it): schedule an automatic rollback. It prevents a simple typo from stranding you.
sudo bash -lc 'echo "ufw disable" | at now + 10 minutes'
If everything checks out afterward, remove the pending job:
atq
atrm <job_id>
Quick triage checklist (what’s broken, exactly?)
Write down what you’re seeing before you change anything. You’ll move faster and avoid “fixing” the wrong layer.
- SSH: timeout vs “connection refused” vs “permission denied”
- Web: site loads but HTTPS fails, or only specific endpoints fail
- Let’s Encrypt: HTTP-01 validation fails (port 80), or TLS-ALPN-01 fails (port 443)
- Email: inbound SMTP (25), submission (587), SMTPS (465), IMAP/POP (143/993/110/995)
Now capture the current firewall state. This gives you a clean baseline.
sudo ufw status verbose
sudo ufw status numbered
sudo iptables -S | sed -n '1,120p'
sudo ip6tables -S | sed -n '1,120p'
If you manage a multi-client node (reseller-style), consider managed VPS hosting. It keeps firewall changes and audits on a controlled process, not “whoever logged in last.”
Confirm what the server is actually listening on (don’t guess ports)
Many “UFW broke it” incidents are really a stopped service. Others are a daemon bound to the wrong interface. Check listeners first.
sudo ss -lntup
sudo ss -lnup | grep -E ':(22|80|443|25|465|587|110|143|993|995)\b'
On a typical hosting VPS, you usually expect:
- SSH:
:22(or a custom port) - HTTP/HTTPS:
:80,:443(Nginx/Apache/LiteSpeed) - Mail:
:25,:587, sometimes:465(Postfix/Exim), plus IMAP/POP if you host mail
If a port isn’t listening, fix the service first. For cPanel/WHM mail specifics, see cPanel mail server setup guide.
Determine whether the problem is UFW, upstream filtering, or DNS
From your laptop, different failures can look identical. Many failures show up as a simple timeout.
Split the problem into a few checks. This helps you avoid chasing ghosts.
1) Test from outside the server
# From your workstation
nc -vz <server_ip> 22
nc -vz <server_ip> 80
nc -vz <server_ip> 443
For email ports:
nc -vz <server_ip> 25
nc -vz <server_ip> 587
2) Test locally on the server
This separates “service is dead” from “network path is blocked.”
curl -I http://127.0.0.1/
curl -Ik https://127.0.0.1/
3) Check UFW logs (the fastest proof)
If logging is off, enable it briefly. Keep it on only long enough to reproduce the issue.
sudo ufw logging medium
Then watch the kernel log for drops:
sudo journalctl -k -f | grep -i ufw
If you see UFW BLOCK with something like DPT=22, you have a direct match. That line ties your symptom to a firewall decision.
Fix scenario #1: “SSH timed out after enabling UFW”
Most SSH lockouts come from two mistakes. SSH wasn’t allowed before UFW was enabled. Or you allowed 22 while sshd is on a custom port.
Step 1: Use console access if you’re locked out
If SSH is already down, log in through your provider console. Then check both UFW and sshd:
sudo ufw status numbered
sudo ss -lntup | grep sshd
Step 2: Allow the real SSH port (and your admin IP when possible)
If SSH listens on 22:
sudo ufw allow 22/tcp
If you moved it to 2222:
sudo ufw allow 2222/tcp
Best practice is to restrict SSH to a known IP. Replace 203.0.113.10 with your real public address.
sudo ufw allow from 203.0.113.10 to any port 22 proto tcp
If your source IP changes often, don’t keep widening the rule. Use a jump box instead of exposing SSH to the world. HostMyCode has a full guide: set up a VPS jump box.
Step 3: Verify before you remove the rollback
sudo ufw reload
sudo ufw status verbose
Open a fresh SSH connection from your workstation. When it works, remove the scheduled ufw disable job (if you created one).
Fix scenario #2: Let’s Encrypt HTTP-01 validation fails (port 80 blocked)
Even in 2026, many renewals fail for a basic reason. Inbound HTTP on :80 never reaches your web server.
UFW is often the culprit.
Step 1: Confirm the validation path needs port 80
HTTP-01 requires Let’s Encrypt to fetch a token over plain HTTP. You can redirect to HTTPS. Port 80 still must accept the request.
First, confirm your web server is listening:
sudo ss -lntup | grep -E ':(80|443)\b'
Step 2: Allow HTTP and HTTPS (use UFW app profiles when available)
On Ubuntu, UFW often includes profiles such as Nginx Full or Apache Full:
sudo ufw app list
sudo ufw allow 'Nginx Full'
# or
sudo ufw allow 'Apache Full'
If profiles aren’t available, allow the ports directly:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
Step 3: Prove the port is reachable from the internet
curl -I http://<your-domain>/.well-known/acme-challenge/test 2>/dev/null | head
A 404 is fine for this synthetic test. A timeout usually points to networking or firewall issues.
If you need the full certificate workflow (Nginx or Apache), follow Let’s Encrypt setup guide. If you run WHM, use the targeted fix list in cPanel AutoSSL troubleshooting.
Fix scenario #3: HTTPS works for some users but not others (IPv6 + UFW)
This issue burns time because it’s inconsistent. IPv4 works, but IPv6 clients fail.
Common causes: UFW isn’t managing IPv6, or your IPv6 policy doesn’t match IPv4.
Step 1: Check if the domain has AAAA records
dig +short AAAA your-domain.com
If you get an IPv6 address back, many clients will try IPv6 first.
Step 2: Ensure UFW is configured for IPv6
Open /etc/default/ufw and confirm:
IPV6=yes
Reload and re-check status:
sudo ufw reload
sudo ufw status verbose
Then confirm ip6tables has UFW chains populated:
sudo ip6tables -S | grep -E 'ufw|UFW' | head
Fix scenario #4: Mail clients time out on 587 (submission) but 25 is open
Port 25 is mostly server-to-server SMTP. Port 587 is for authenticated sending by users and apps.
If 587 is blocked, you’ll see timeouts in Outlook, mobile clients, and SMTP libraries.
Step 1: Verify what’s listening
sudo ss -lntup | grep -E ':(25|587|465)\b'
If 587 isn’t listening, fix your MTA configuration (Postfix/Exim). If it is listening, move on to UFW rules.
Step 2: Allow the correct ports (minimal set)
sudo ufw allow 25/tcp
sudo ufw allow 587/tcp
# Only if you intentionally offer SMTPS
sudo ufw allow 465/tcp
Only open IMAP/POP if you actually provide mailbox access:
sudo ufw allow 993/tcp
sudo ufw allow 995/tcp
Step 3: Confirm you’re not failing on DNS reputation prerequisites
Open ports don’t guarantee mail works. If reverse DNS is missing or incorrect, deliverability often fails even when connections succeed.
Use these guides:
Fix scenario #5: You allowed “80,443” but your site still breaks (wrong interface or deny precedence)
UFW is simple, but specificity and rule ordering still matter. These mistakes show up constantly:
- Allowing
80on IPv4 only (see the IPv6 section). - Adding a broad deny later, such as
deny in on eth0. - Allowing from a source IP that doesn’t match the real client IP (VPN, NAT gateway, office proxy).
Step 1: Inspect numbered rules and look for broad denies
sudo ufw status numbered
If a broad deny overlaps your allow, results get confusing.
The cleanest fix is usually to delete the bad rule by number, then re-test.
sudo ufw delete 2
Step 2: Verify the route and interface used for traffic
On multi-interface servers, rules can be correct but applied to the wrong NIC. Check routes for IPv4 and IPv6:
ip route
ip -6 route
Useful diagnostics: see what UFW is doing under the hood
If ufw status doesn’t explain it, inspect the underlying tables.
sudo iptables -L -n -v | sed -n '1,160p'
sudo iptables -t nat -L -n -v | sed -n '1,160p'
Docker and some control panels change iptables directly. NAT and filter interactions can get weird fast.
To stop guessing, capture packets while you attempt a connection:
sudo tcpdump -ni any 'tcp port 22 or tcp port 80 or tcp port 443'
If packets arrive but the connection still fails, focus on the service or upstream filtering.
If packets never arrive, check provider security groups, edge firewalls, or DNS pointing to the wrong host.
Harden after the fix: safer defaults for hosting servers
Troubleshooting often ends with “open everything until it works.” Don’t leave the server that way.
A sane baseline for a web + mail VPS looks like this:
- Allow: 22 (restricted), 80, 443
- Allow mail only if you run mail: 25, 587, 465 (optional), 993/995 (optional)
- Deny: everything else inbound
Set explicit defaults so you know where you stand:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw status verbose
If you want to go beyond firewall rules (sudo scope, session logging, least privilege), follow SSH access control tutorial.
Operational checklist: how to change UFW on production without surprises
- Open a second SSH session before changes.
- Confirm listeners with
ss -lntup. - Make one change at a time. Reload and test immediately.
- Use
ufw status numberedand delete by number. Avoid editing guesses. - Enable logging briefly during incidents, then reduce it.
- Document which ports exist for which service (especially mail).
- After fixes, tighten SSH to a trusted IP or a bastion host.
Summary: a repeatable UFW troubleshooting workflow
Start with the symptom. Confirm what’s listening.
Next, prove whether packets reach the box and whether UFW drops them.
Change the smallest rule that fixes the problem. Then tighten things back down.
That loop prevents two classic failures. You avoid debugging the wrong layer. You also avoid “temporarily” opening the firewall forever.
If you want infrastructure that stays predictable during routine admin work (firewall updates, SSL renewals, mail tweaks), run your workloads on HostMyCode VPS and scale to HostMyCode dedicated servers when you need isolated performance for busy sites or reseller nodes.
If you’re adjusting firewall rules during a migration or after a security cleanup, a stable hosting baseline makes every change less risky. HostMyCode offers managed VPS hosting for teams that want changes reviewed and applied safely, plus straightforward VPS hosting when you prefer full control.
FAQ
Should I use UFW app profiles or port rules?
Use app profiles when they exist (Nginx Full, Apache Full) because the rules stay readable. Use explicit ports for mail and any custom services.
Why does SSH “connection refused” happen if UFW is blocking?
“Refused” usually means nothing is listening on that port, or a TCP reset is being sent. UFW drops more often show up as timeouts. Confirm with ss -lntup and UFW logs.
Do I need to open port 80 if I force HTTPS?
Yes. You need port 80 for HTTP-01 certificate validation and for clean redirects. Keep 80 open and redirect to HTTPS in the web server.
What’s the safest way to avoid SSH exposure on a public VPS?
Restrict SSH to a fixed source IP, or use a bastion (jump host). A jump host keeps SSH closed to the internet while preserving admin access.
How do I tell if it’s UFW or my hosting provider blocking the port?
If tcpdump on the server shows no incoming packets during an external test, the traffic is being blocked upstream (edge firewall, security group, wrong DNS) rather than by UFW.