Skip to content
Webmaster Tools
SecurityPort ScannerPort 80 (HTTP)

Port 80 (HTTP)

Port 80 is plain HTTP. Why it should stay open to redirect to HTTPS and pass ACME challenges, firewall rules, and how to fix "port 80 already in use".

What runs on port 80

TCP port 80 is the default port for HTTP, unencrypted web traffic. When you type example.com or http://example.com in a browser, it connects to port 80 unless it already knows the site uses HTTPS. Nothing on port 80 is encrypted, so login forms, cookies and API tokens should never be sent over it. Real content belongs on port 443.

Should it be open to the internet?

On a public web server, yes, but only to redirect. Keep port 80 open so that:

  • visitors who type the bare domain get a 301 redirect to HTTPS instead of a connection error;
  • Let's Encrypt and other ACME clients can complete the HTTP-01 challenge, which always connects to port 80;
  • old links and bookmarks with http:// still work.

A minimal nginx server block:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt;
    }

    location / {
        return 301 https://example.com$request_uri;
    }
}

Add an HSTS header on the HTTPS side so browsers skip port 80 on later visits. Our Security Headers Checker shows whether it is set.

Firewall rules:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# or both at once with the nginx profile
sudo ufw allow 'Nginx Full'
iptables -A INPUT -p tcp --dport 80 -j ACCEPT

If the server is not a public web server (a database host, an internal box), keep 80 closed.

See what is listening

sudo ss -tlnp 'sport = :80'
sudo lsof -i :80

To test from outside: curl -I http://example.com. A 301 with a Location: https://… header is what you want to see.

"Port 80 already in use"

nginx fails with bind() to 0.0.0.0:80 failed (98: Address already in use) and Docker with Bind for 0.0.0.0:80 failed: port is already allocated when another process holds the port. Common culprits:

  • Apache and nginx both installed; the package for one starts it automatically. sudo systemctl disable --now apache2 (or httpd).
  • An old container still running: docker ps and stop it.
  • A second copy of the same server, or a crashed one still holding the socket.
  • Another web tool such as Caddy or Traefik already acting as the front proxy.

Find the process with sudo ss -tlnp 'sport = :80', stop it, then start yours. If both must run, put one behind the other as a reverse proxy on a different port such as 8080.

Privileged port

Ports below 1024 are privileged on Linux: a normal user cannot bind them. Web servers start as root and drop privileges, or get the capability:

sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/myserver

A Node, Python or Go app is usually better left on a high port such as 3000 behind nginx.

Security notes

  • Don't serve content on 80 that should be private; redirect everything except ACME challenges.
  • Redirect to the same host on HTTPS first, then to the canonical host, so HSTS can apply.
  • Check your redirect chain; extra hops slow every first visit.

See every hop from http:// to your final page with the Redirect Checker, or check open ports with the Port Scanner.