> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Firewall Ports Install Config

> Guide to using UFW on Ubuntu to enable and configure firewall rules for NGINX, SSH, and Flask, and best practices like reverse proxying backend services.

Earlier we verified NGINX from inside the server using `curl localhost`. Those local checks are essential for troubleshooting on the host, but they do not show how a remote client (browser or external curl) experiences the services — or how a host firewall (UFW) affects access.

In this lesson you'll learn to use UFW (Uncomplicated Firewall) on Ubuntu to control which ports are reachable from the internet. We'll show the commands and expected outputs for enabling UFW and adding rules for HTTP, HTTPS, and SSH. We also cover safe patterns for exposing backend services (like a Flask app) via a reverse proxy instead of opening nonstandard ports.

## Overview of services on the host

| Service | Port | Purpose |
| -: | :-: | - |
| NGINX | 80 (HTTP) | Serves the default "Welcome to nginx!" page |
| Flask app | 5000 | Simple backend application (development/demo) |
| UFW (firewall) | n/a | Controls which ports are reachable from external clients |

Initially the firewall is inactive, so both ports are reachable from outside. We'll enable UFW and restrict access to just the ports we want.

## Quick local checks (server-side)

From the server shell you can confirm both services are responding using `curl`. These are local checks and only validate that the services are listening on the expected ports.

```bash theme={null}
# NGINX (port 80)
bob@alpine-host ~ ➜ curl localhost
```

```html theme={null}
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
```

```bash theme={null}
# Flask app (port 5000)
bob@alpine-host ~ ➜ curl localhost:5000
```

```html theme={null}
<h1>Hello, Human!</h1>[Not Authenticated]
```

These responses confirm both services are functioning locally. To simulate an external client you would use a browser or run `curl` against the host's public IP or domain.

## Convenience UIs vs. proper firewall rules

Some cloud or development environments offer a “View ports” or similar UI that temporarily exposes a host port to your browser. That can be useful for demos but should not replace proper firewall configuration in production. Use UFW (or your cloud provider’s security groups/load balancer) to manage access in a secure, repeatable way.

## Enable UFW and add port rules

Best practice is to enable the firewall and open only the ports you need — typically 80 and 443 for web traffic, and 22 for SSH (preferably restricted to known IPs).

Start by checking UFW status, enable it, and add rules:

```bash theme={null}
# Check status (before enabling)
bob@alpine-host ~ ➜ sudo ufw status
Status: inactive
```

```bash theme={null}
# Enable UFW (this activates the firewall and ensures it starts on boot)
bob@alpine-host ~ ➜ sudo ufw enable
Firewall is active and enabled on system startup
```

```bash theme={null}
# Allow HTTP (port 80)
bob@alpine-host ~ ➜ sudo ufw allow 80/tcp
Rule added
Rule added (v6)
```

```bash theme={null}
# Re-check status after opening port 80
bob@alpine-host ~ ➜ sudo ufw status
Status: active

To                         Action      From
--                         ------      -----
80/tcp                     ALLOW       Anywhere
80/tcp (v6)                ALLOW       Anywhere (v6)
```

At this point port 80 is allowed from both IPv4 and IPv6. Other ports remain blocked.

If you need to expose the Flask app directly for development (not recommended for production), add port 5000:

```bash theme={null}
# Allow Flask port (5000)
bob@alpine-host ~ ➜ sudo ufw allow 5000/tcp
Rule added
Rule added (v6)
```

```bash theme={null}
# Status shows both ports allowed
bob@alpine-host ~ ➜ sudo ufw status
Status: active

To                         Action      From
--                         ------      -----
80/tcp                     ALLOW       Anywhere
5000/tcp                   ALLOW       Anywhere
80/tcp (v6)                ALLOW       Anywhere (v6)
5000/tcp (v6)              ALLOW       Anywhere (v6)
```

### Allow SSH (port 22) before disconnecting

Important: If you’re connected over SSH, allow port 22 before you enable UFW or before you end your session — otherwise you may lock yourself out.

```bash theme={null}
bob@alpine-host ~ ➜ sudo ufw allow 22/tcp
Rule added
Rule added (v6)
```

```bash theme={null}
# Final status includes SSH, HTTP and any other allowed ports
bob@alpine-host ~ ➜ sudo ufw status
Status: active

To                         Action      From
--                         ------      -----
80/tcp                     ALLOW       Anywhere
5000/tcp                   ALLOW       Anywhere
22/tcp                     ALLOW       Anywhere
80/tcp (v6)                ALLOW       Anywhere (v6)
5000/tcp (v6)              ALLOW       Anywhere (v6)
22/tcp (v6)                ALLOW       Anywhere (v6)
```

## Commands summary

| Command | Purpose |
| -: | :- |
| `sudo ufw status` | Check UFW status and rules |
| `sudo ufw enable` | Enable firewall and auto-start on boot |
| `sudo ufw allow 80/tcp` | Allow HTTP traffic (port 80) |
| `sudo ufw allow 443/tcp` | Allow HTTPS traffic (port 443) |
| `sudo ufw allow 22/tcp` | Allow SSH (port 22) — do this before disconnecting |
| `sudo ufw allow 5000/tcp` | Example: allow a development Flask app (not recommended in prod) |

Do not make backend applications publicly reachable on nonstandard ports (like 5000) unless absolutely necessary. Publicly exposing these ports can cause usability and security issues — most users expect websites on ports 80/443 and may omit port numbers in URLs.

Prefer exposing backend apps (for example, a Flask app on port 5000) through a reverse proxy or load balancer. Configure NGINX (or a cloud load balancer) to listen on 80/443 and forward requests internally to the backend port. This keeps only 80/443 (and SSH) open to the internet while backend services remain inaccessible directly.

## Quick best-practice checklist

* Open only the ports you need. For public web services: 80 and 443. For administration: 22, ideally restricted to trusted IPs.
* Use a reverse proxy (NGINX) or load balancer to expose backend services on standard ports, instead of opening backend ports to the internet.
* Always enable UFW and verify rules before closing your administrative session.
* For production, enforce HTTPS (443) and consider automated certificate management (e.g., Let's Encrypt).

## Links and references

* [UFW — Uncomplicated Firewall](https://help.ubuntu.com/community/UFW)
* [NGINX documentation](https://nginx.org/en/docs/)
* [Flask documentation](https://flask.palletsprojects.com/)
* [Let's Encrypt — Free SSL/TLS certificates](https://letsencrypt.org/)

> **[Watch Video](https://learn.kodekloud.com/user/courses/nginx-for-beginners/module/0de43784-b08d-4ce0-8470-a7541b78fe58/lesson/794628cb-4836-49d0-828f-6248c05f4b83)**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.