How to Configure a UFW Firewall on a VPS
Configure a UFW firewall on a self-hosted VPS the right way: default deny, allow only what you serve, and keep your database off the public internet for good.
A VPS firewall has one job: allow the handful of ports you actually serve and deny everything else. UFW, the uncomplicated firewall, is the easiest way to do that on Linux, and the correct configuration is short. Default deny inbound, allow SSH and your web ports, and make sure your database is never reachable from the public internet. I set this up on every box in my portfolio in about two minutes, and it is the backstop that catches the mistakes: a service that binds to the wrong interface, a debug port left open, a config that exposes more than you meant.
Start with default deny
The whole philosophy of a good firewall is that everything is blocked unless you explicitly open it. This is the opposite of the default on a fresh box, where services can bind to any port and the internet can reach them. Flip it.
ufw default deny incoming: nothing gets in unless you allow it.ufw default allow outgoing: your box can still reach the internet to pull updates and push backups.
With this in place, the firewall is closed by default and you open exactly the doors you need. If you forget to open something, the symptom is "I cannot reach my service," which you notice immediately and fix. That failure mode is far safer than the reverse, where you accidentally expose something and never notice until it is abused.
Allow only what you serve
Now open the specific ports. For a typical web app on a box behind one reverse proxy, that is a very short list.
- SSH, so you can manage the box. Restrict it to your own IP if you have a static one.
- HTTP and HTTPS, so the proxy can serve traffic.
- Nothing else facing the world.
Enable UFW and it enforces the rules. That is the entire public surface of a well-run app server: your management door and your web ports. Everything else, and there is always more running than you think, stays invisible from outside. Keep this list as short as your architecture allows, because every open port is a thing you now have to reason about.
Keep your database off the public internet
This is the mistake I see most often, and it is the one that hurts. People run Postgres or Redis, bind it to all interfaces, and the firewall never stops the port because they never thought about it. Now the database is reachable from anywhere, protected only by a password, and that is not a position you want to be in.
The fix is layered. First, bind the database to localhost or a private network interface only, so it is not listening on the public IP at all. Second, do not open its port in UFW. Between those two, the database is doubly unreachable from outside. When I run one Postgres box for every app, the apps reach it over a private network, and the public firewall never has that port open. The internet does not know the database exists.
Do not lock yourself out
The one way UFW bites you is closing your own SSH session. Before you enable the firewall, make sure the SSH rule is in place. Confirm you can open a second session with the rule active before you trust it. If you restrict SSH to a single IP, be certain that IP is right and stable, because getting it wrong means locking yourself out of the box.
Most providers give you a console or recovery mode that bypasses the firewall, so a lockout is recoverable, but it is a hassle you can avoid by checking your access before you rely on the rules. This is the same care I take when hardening SSH: never remove your current access until you have confirmed the new access works.
The firewall is a backstop, not the whole plan
A firewall does not replace the rest of your security. It does not patch your software, it does not stop a brute-force attempt against a port you legitimately serve, and it does not protect an application with a vulnerability. It is the layer that limits blast radius: even if a service misbehaves, the port is simply not open to the world. Pair it with automatic security updates and a brute-force ban, and you have a solid base.
I run UFW with default deny on every VPS in my portfolio, hosted through HostSSH. Two minutes of setup, and the box only answers on the doors I chose. Deny by default, open what you serve, and keep the database private. That is the whole configuration, and it prevents the exposures that quietly sink self-hosted setups.