
August 15, 2026
9 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
Leaving a production server exposed without a host-based firewall is a risk no amount of application-level patching can fix. Configuring UFW firewall rules for web servers correctly blocks automated scanners, restricts database access, and ensures only intended traffic reaches your Laravel, WordPress, or Node.js applications. This guide provides the exact commands and verification steps I use on Ubuntu 24.04 LTS systems hosting client projects in Nepal and abroad.
ufw enable, and verify active rules with ufw status verbose. Always confirm SSH access before enabling to prevent lockout.How Do You Safely Enable UFW Firewall Rules for Web Servers Without Locking Yourself Out?
The most common disaster when configuring server security in Nepal or anywhere else is enabling UFW without first allowing SSH. The firewall defaults to denying all incoming connections, and if port 22 isn't whitelisted, you lose access immediately. On remote VPS instances where console access requires a provider dashboard, this turns a five-minute task into an hour-long recovery.
I follow this exact sequence on every new Ubuntu 22.04 or 24.04 server before deploying any application:
- Verify current SSH connection: Confirm you're connected via SSH and know the port. If you've changed SSH from port 22 to something like 2222, adjust commands accordingly.
- Set default policies: Run
sudo ufw default deny incomingandsudo ufw default allow outgoing. This establishes a secure baseline without activating enforcement yet. - Allow SSH explicitly: Run
sudo ufw allow 22/tcp(or your custom SSH port). Use/tcpto avoid opening UDP unnecessarily. - Enable UFW: Run
sudo ufw enable. You'll see a warning that existing SSH sessions may be disrupted; since SSH is already allowed, confirm withy. - Test immediately: Open a new terminal window and SSH into the server. Don't close your existing session until the new one connects successfully.
This order matters because UFW applies rules atomically when enabled. Setting defaults first, then adding exceptions, then enabling ensures there's never a window where SSH is blocked. On legal-tech portals like Court Marriage In Nepal or Notary Nepal, where uptime directly affects clients needing urgent document processing, I've seen this discipline prevent costly outages during initial hardening.
Which UFW Firewall Rules for Web Servers Are Essential for Laravel and PHP Applications?
Laravel applications running on Nginx or Apache with PHP-FPM need more than just ports 80 and 443. Queue workers, scheduled tasks, and debugging tools each have specific network requirements that must be reflected in your UFW configuration. Based on deployments for projects like Nepal Gift Card and Adventure Third Pole Trek, these are the rules I apply consistently:
# Core web traffic
sudo ufw allow 80/tcp # HTTP (redirects to HTTPS)
sudo ufw allow 443/tcp # HTTPS (primary application traffic)
# SSH management
sudo ufw allow 22/tcp # Or custom SSH port
# Laravel-specific services (restrict by IP in production)
sudo ufw allow from 127.0.0.1 to any port 6379 proto tcp # Redis (local only)
sudo ufw allow from 127.0.0.1 to any port 3306 proto tcp # MySQL (local only)
# Optional: Laravel Telescope/Horizon (development/staging only)
sudo ufw allow from 103.69.124.0/24 to any port 8080 proto tcp # Office IP range A critical pattern here is binding database and cache ports to localhost. Redis and MySQL should never accept connections from arbitrary IPs. Even if your application server and database are on the same machine, using from 127.0.0.1 prevents external exploitation if a service misconfiguration accidentally binds to 0.0.0.0. For multi-server setups where the database lives elsewhere, replace 127.0.0.1 with the specific private IP of the application server.
For Laravel queue workers using Redis or database drivers, no additional inbound ports are needed since queues are internal processes. However, if you're running Laravel Horizon on a non-standard port for monitoring, restrict it to trusted IPs only. I've audited Laravel applications in Nepal where Horizon was publicly accessible without authentication—a single misconfigured UFW rule away from exposing sensitive job data.
Handling Let's Encrypt Certificate Renewals
Certbot HTTP-01 challenges require port 80 to be open. Since we already allow HTTP for redirects, this works automatically. If you're using DNS-01 challenges instead (common for wildcard certificates), no additional UFW rules are needed since validation happens via DNS records, not inbound HTTP.
How Do UFW Firewall Rules Differ Between Nginx, Apache, and Node.js Web Servers?
While the core principles remain the same, each web server has distinct operational characteristics that affect firewall configuration. Understanding these differences prevents both over-permissive rules and accidental service breakage.
| Criteria | Nginx + PHP-FPM | Apache + mod_php | Node.js (Express/Nest) |
|---|---|---|---|
| Primary ports | 80, 443 | 80, 443 | 80, 443 (reverse proxy) or 3000/8080 (direct) |
| Internal process ports | PHP-FPM socket or 9000 (local) | None (embedded) | None if reverse-proxied; app port if direct |
| Static file serving | Nginx handles directly | Apache handles directly | Typically reverse-proxied through Nginx |
| WebSocket support | Requires proxy_pass upgrade headers | mod_proxy_wstunnel | Native; ensure proxy preserves Upgrade header |
| Common mistake | Exposing PHP-FPM port 9000 externally | Leaving mod_status publicly accessible | Running Node directly on 80/443 without reverse proxy |
| Recommended setup | Nginx as frontend, PHP-FPM on Unix socket | Apache with mpm_event + PHP-FPM | Nginx reverse proxy → Node on localhost:3000 |
For Node.js applications, I strongly recommend always placing Nginx or Caddy in front rather than exposing Node directly. This lets UFW manage only standard web ports while Node listens solely on localhost. Direct Node exposure means managing TLS termination, static files, and compression at the application level—all better handled by a dedicated reverse proxy. On eCommerce platforms like Quick And Easy Nepalese Grocery, this architecture simplified both security and performance tuning.
How Do You Restrict Database and Cache Ports Using UFW on Production Servers?
Databases and caches are frequent attack vectors when accidentally exposed to the internet. MySQL, PostgreSQL, Redis, and MongoDB should never accept connections from untrusted networks. UFW makes this straightforward with source-address restrictions, but the syntax trips people up.
# MySQL - local application only
sudo ufw allow from 127.0.0.1 to any port 3306 proto tcp comment 'MySQL local'
# PostgreSQL - allow from specific app server in private network
sudo ufw allow from 10.0.1.50 to any port 5432 proto tcp comment 'PostgreSQL app-server'
# Redis - strictly local (never expose remotely without TLS + auth)
sudo ufw allow from 127.0.0.1 to any port 6379 proto tcp comment 'Redis local'
# MongoDB - bind to localhost in mongod.conf AND restrict via UFW
sudo ufw allow from 127.0.0.1 to any port 27017 proto tcp comment 'MongoDB local' Note the proto tcp specification. Omitting it opens both TCP and UDP, which is unnecessary for these services and widens the attack surface. The comment flag is optional but invaluable when auditing rules months later—I can immediately see why each rule exists without checking documentation.
For servers where the database runs on the same host as the application, consider skipping UFW rules for database ports entirely and relying solely on the service's own bind-address configuration (e.g., bind-address = 127.0.0.1 in MySQL's my.cnf). Defense in depth is good, but if the service only listens on localhost, UFW rules for that port are redundant. Reserve UFW restrictions for cases where the service must listen on a non-loopback address for legitimate reasons, such as replication or multi-server architectures.
IPv6 Considerations for Modern Deployments
Ubuntu enables IPv6 in UFW by default when /etc/default/ufw contains IPV6=yes. Rules specified without an explicit version apply to both IPv4 and IPv6. However, from 127.0.0.1 only matches IPv4 loopback. For dual-stack localhost restrictions, add a companion rule:
sudo ufw allow from ::1 to any port 3306 proto tcp comment 'MySQL local IPv6' If your server doesn't use IPv6 externally, you can safely leave IPv6 enabled in UFW for localhost services without exposing anything. Disabling IPv6 entirely (IPV6=no) is unnecessary and can break local service communication on modern Ubuntu systems.
What Is the Correct Way to Manage UFW Rules During Deployment and Maintenance?
Firewall rules shouldn't be managed ad-hoc on live servers. Treat them as infrastructure code. On projects using Deployer 7 with GitLab CI—including sister sites like notarykathmandu.com and translationnepal.com—I include UFW configuration in the provisioning phase, separate from application deployment.
- Provisioning (Ansible/cloud-init): Define base rules (SSH, HTTP, HTTPS) during server creation. This ensures every server starts with a known-good firewall state.
- Application deployment: Avoid modifying UFW during deploys unless absolutely necessary. If a new service requires a port, add it to the provisioning playbook first, test in staging, then apply to production.
- Rule auditing: Run
sudo ufw status numbered verbosemonthly. Numbered output makes deletion precise (sudo ufw delete 3). Verbose shows hit counts, revealing unused rules. - Emergency access: Maintain a documented procedure for temporary IP whitelisting during incidents.
sudo ufw prepend allow from 203.0.113.45 to any port 22adds a rule at the top without disrupting existing ordering.
One gotcha I've encountered repeatedly: after deleting a rule by number, remaining rule numbers shift. Always re-run ufw status numbered before subsequent deletions. Better yet, delete by specification (sudo ufw delete allow 80/tcp) to avoid numbering confusion entirely.
Securing Your Server Starts With Correct UFW Firewall Rules for Web Servers
Getting UFW firewall rules for web servers right is foundational infrastructure work that pays dividends in security, compliance, and peace of mind. The commands and patterns here reflect real configurations running on production systems today—from legal-tech portals handling sensitive client documents to eCommerce platforms processing payments via eSewa and Khalti. Start with the safe enablement sequence, layer in application-specific restrictions, and treat your firewall as code rather than afterthought. If you need help auditing your server's firewall configuration or implementing these rules on an existing deployment, reach out to discuss your infrastructure needs.

