Your VPS has a public IP and, by default, every port is open. ufw is the easy, safe way to close the doors you don't use — without ever touching iptables.
← / → to navigate · EN/VI switch below · the operator's view — mental model first, a handful of small examples
The moment you buy it, your machine has a public IP — and there is no firewall in front of it by default.
Your VPS has an address like 203.0.113.10. Anyone can send packets to any port on it — and the bots know every address that exists.
A default VPS has no firewall: SSH :22, MySQL :3306, Postgres :5432, Redis :6379 — if a service is listening, the whole world can reach it.
Bots scan the entire internet for open ports around the clock. An exposed Redis or database is found within hours — and the bots already carry the exploits.
Your website should stay reachable — your databases and SSH should not. Something has to stand in front and decide, per port, who may come in.
No firewall yet — every service answers anyone who knocks.
Same machine you'll use to ship your app — except right now, a stranger from anywhere can talk to MySQL directly. That's the problem this deck fixes.
A good firewall is invisible: set it up once, open only the doors you need, and never think about it again — until something unexpected shows up in the log.
One tool, three properties: easy, safe by default, and stateful. Get these and every command becomes obvious.
ufw (Uncomplicated Firewall) is a friendly command-line front-end to the real packet filters — iptables and nftables. It translates your one-line rules into what the kernel actually executes. You never need to touch the raw filter language.
The moment you run ufw enable, the posture flips: deny everything coming in, allow everything going out. From then on, you only open the specific doors you need.
It tracks connections: if your machine started the conversation, the reply is allowed automatically. That's what makes 'deny inbound' safe — in a minute we'll see why.
On a typical Ubuntu VPS, ufw is preinstalled and just sitting there, inactive — waiting for you to turn it on. One command later, your VPS stops answering strangers.
After ufw enable, every connection coming from outside is refused — unless you added an explicit allow rule for that port. The default answer to strangers is 'no'.
That's the whole security model in one sentence: nothing gets in unless you opened that door yourself.
Your VPS still talks to the outside world freely — apt updates, DNS lookups, your app calling an external API or database. Outbound stays open by default.
So your site keeps working — while the doors the world can walk through stay locked.
You click, your browser asks for a page. Two directions of traffic — ufw treats them differently, for a good reason.
The gatekeeper keeps a notebook of who it let out. Anything coming back on one of those conversations passes without a second question. A stranger who knocks first still gets a 'no'.
The kernel keeps a table of active connections: 'laptop → 203.0.113.10:443, started 5 seconds ago, still talking'. Every packet is checked against that table first, not against a blind list of rules.
Think of ufw as a building with a strict reception: nobody gets in unless you invited them. But if you went out to buy coffee, the barista can walk you right back in — your card is already on the guest list.
Your app calls external APIs, apt pulls updates, browsers fetch your pages. Statefulness is what lets all of that keep working while 'deny inbound' holds the line against strangers.
Five verbs cover 95% of daily firewall work: enable, status, allow, deny, delete — plus one line for the global defaults.
Turns the firewall on — immediately, and at every boot. Until this runs, ufw is a notebook with no gatekeeper: your rules exist, but nothing is actually filtered.
Shows whether ufw is active and lists every rule in effect, with its action (ALLOW / DENY) and direction. This is the first thing you type after every change.
The same view, plus the default incoming/outgoing policy and whether logging is on. Good for the quick 'is everything the way I think it is?' check.
Note the warning — that's ufw being honest with you about SSH (the golden rule comes later).
Opens a door: traffic on that port may come in from anywhere. Works with a port number (22/tcp, 8080/tcp) or a service name (OpenSSH, 'Nginx Full'). Add /udp for services that speak UDP.
Closes a door explicitly. Handy when the default already denies — it documents your intent, and gives you a hook for logging the noise or allowing one specific IP later.
Removes a rule you added earlier: ufw delete allow 3306/tcp. Delete doesn't 'deny' — it puts the port back to whatever the default policy says.
Every rule is a single line in ufw's notebook. That's the whole data model — no config files to hunt for, no restart needed. The notebook is saved on disk and reloaded at boot.
# turn it on (now + at every boot)
sudo ufw enable
# what's actually active?
ufw status
# the daily drivers
ufw allow 22/tcp # SSH, by port number
ufw allow OpenSSH # same rule, by service name
ufw allow 'Nginx Full' # 80 + 443 in one go
ufw deny 3306/tcp # MySQL: no outside traffic
ufw delete deny 3306/tcp # undo that rule
Everything here is one line, reversible, and shows up instantly in ufw status. No config file, no restart.
SSH plus the two web ports. That's the entire firewall for most small projects — nothing else open.
The global 'strangers get a no'. This is the policy that makes everything not explicitly allowed unreachable. It's already the default after enable — but stating it out loud is good hygiene.
The global 'your VPS can reach the world'. Outbound stays open so updates, DNS lookups and your app's API calls keep working.
Think of it as the policy for every port you forgot about: 3306, 5432, 6379, 10000… Anything without an explicit allow inherits 'deny incoming'. That long tail is exactly what scanners are after.
How to think about the whole thing in one sentence — and the one mistake that costs you an evening.
Three doors open for the people who need them; everything else gets a 'no' before it ever reaches a service.
The scanner keeps knocking on 3306 and 5432 — and gets nothing. Your users get your website, and only you get the shell.
Firewall changes are dangerous: a wrong deny or delete can cut your own SSH — and there is no 'undo' from outside.
You manage the VPS through SSH. If a rule blocks :22, you can't get in — not even to fix it. The fix then happens through your provider's web console (VNC/rescue), which is slow and unpleasant.
Before ufw enable — or any deny/delete — make sure an allow rule for your SSH port exists. If your SSH runs on a non-standard port, that's the one to allow.
Open a SECOND terminal before you tighten things, and test that you can still connect. If the new session dies, the old one is still in — you get 30 seconds to delete the bad rule.
Four moves, in this order, every single time.
ufw allow 22/tcp (or whatever port your SSH listens on). This rule must exist before anything else gets stricter.
sudo ufw enable — the default posture kicks in: deny incoming, allow outgoing. Your SSH rule keeps you in.
From your machine, open another SSH session. It connects? You're safe to continue. It doesn't? Your first session is still alive — fix the rule from there.
Add the allows for your real services, deny what should be closed, and read ufw status to confirm the final state matches your intent — every time.
Starts recording every dropped or rejected packet: source IP, destination port, protocol. It's forensic evidence of who's probing your box and when.
Entries go to the kernel log — /var/log/kern.log — lines like 'IN=eth0 ... PROTO=TCP DPT=3306 ... REJECT'. tail -f it and watch the scanners work.
ufw logging on is the default after enable, and the overhead on a small VPS is negligible. The day a port gets hammered, you'll be glad the notebook was open.
The real machinery in the kernel: chains, tables, raw rules. Extremely powerful, extremely verbose — and one typo away from blocking yourself out.
A friendly one-line front-end that writes the same kernel rules for you, keeps sane defaults, and can undo them just as easily. For 95% of VPS work, you stop at ufw.
ufw is the gatekeeper in front of your services: open only the doors you need, and let the rest of the internet knock on a locked wall.
ufw enable → allow your SSH → verify from a second terminal → allow 80/443 → the rest stays closed. Ship the app; the gatekeeper's got the door.