A practical port map for hosting
In hosting, “what must be open” is mostly a short list of well-known ports plus a clear understanding of direction: inbound (to your server) versus outbound (from your server). Your goal is to open only what is required for the role of each system (web, DNS, mail, database), and to scope who can reach it (the whole internet, a private subnet, or a few admin IPs).
Common hosting ports (quick reference)
- HTTP: TCP/80 (public web traffic; often redirects to HTTPS)
- HTTPS: TCP/443 (public encrypted web traffic)
- SSH: TCP/22 (administration; should be restricted)
- DNS: UDP/53 (typical queries) and TCP/53 (zone transfers and large responses/fallback)
- DHCP: UDP/67 (server) and UDP/68 (client) (usually internal only)
- SMTP (server-to-server): TCP/25
- Mail submission: TCP/587 (STARTTLS) and sometimes TCP/465 (implicit TLS)
- MySQL/MariaDB: TCP/3306 (should almost never be public)
- PostgreSQL: TCP/5432 (should almost never be public)
- ICMP: not a port (used for reachability/diagnostics like ping and path MTU discovery)
- Ephemeral ports: client-side temporary ports (used for return traffic and outbound connections)
Web: 80 and 443 (what to open and why)
For a public website, you typically allow inbound TCP/443 from the internet to your load balancer or web server. TCP/80 is commonly allowed to support HTTP-to-HTTPS redirects and ACME/Let’s Encrypt HTTP validation (depending on your certificate method). If you run only HTTPS and have an alternate certificate validation method, you may choose to close 80.
Practical inbound rules (typical)
- Allow inbound TCP/443 from 0.0.0.0/0 and ::/0 to the public web endpoint.
- Optionally allow inbound TCP/80 from 0.0.0.0/0 and ::/0 for redirects/validation.
- Do not open admin panels on random ports to the internet; put them behind VPN, a bastion, or IP allowlists.
Step-by-step: verify 80/443 from outside
- From a machine on the internet (not inside the same VPC/VNet), test TCP reachability:
nc -vz yourdomain.example 443 nc -vz yourdomain.example 80 - Test application response:
curl -I https://yourdomain.example/ curl -I http://yourdomain.example/ - If 80 works but 443 fails, treat it as either (a) firewall/security group issue, (b) listener/service issue, or (c) load balancer/certificate issue. The drills below walk you through isolating it.
SSH: 22 (open narrowly, not broadly)
SSH is the most common management entry point for Linux servers. In hosting, the best practice is to avoid exposing SSH to the entire internet. Instead, restrict inbound TCP/22 to known admin IPs (office, VPN egress, bastion host) or keep it private-only and access via a jump host.
Practical inbound rules (typical)
- Allow inbound TCP/22 only from a small set of trusted public IPs (e.g., your VPN egress IP).
- Prefer a bastion host: only the bastion is reachable on 22; internal servers allow 22 only from the bastion’s private IP/security group.
- Outbound rules usually allow ephemeral ports and established connections; SSH itself is inbound to the server.
Step-by-step: confirm SSH is restricted correctly
- From an allowed admin IP, test:
ssh -v user@server-public-ip - From a non-allowed network (e.g., mobile hotspot), test again; it should time out (not succeed). If it succeeds, your rule scope is too broad.
- On the server, confirm the service is listening:
ss -tlnp | grep ':22'
DNS: 53 UDP and TCP (both matter)
If you host authoritative DNS (nameserver) or run a recursive resolver for your infrastructure, you must account for both UDP/53 and TCP/53. UDP handles most queries efficiently. TCP is required for zone transfers (AXFR/IXFR) and is also used when responses are too large for UDP or when DNSSEC/EDNS0 triggers fallback behavior.
Practical rule patterns
- Authoritative public DNS: allow inbound UDP/53 and TCP/53 from the internet to the nameserver(s).
- Internal resolver: allow inbound UDP/53 and TCP/53 only from internal subnets; block internet access.
- Zone transfers: allow inbound TCP/53 only from your secondary DNS servers’ IPs (not from everywhere).
Step-by-step: test DNS over UDP and TCP
- Test UDP query:
dig @your-dns-server example.com A - Force TCP query:
dig +tcp @your-dns-server example.com A - If UDP works but TCP fails, large responses, DNSSEC, or zone transfers may break. If TCP works but UDP fails, typical browsing will feel “down” even though some tools succeed.
DHCP: 67/68 (usually internal only)
DHCP uses UDP/67 (server) and UDP/68 (client). In most cloud hosting designs, DHCP is provided by the cloud platform inside the virtual network, not by your instances. If you do run DHCP (common in on-prem or specialized lab environments), it should never be exposed to the public internet.
Continue in our app.
You can listen to the audiobook with the screen off, receive a free certificate for this course, and also have access to 5,000 other free online courses.
Or continue reading below...Download the app
Practical rule patterns
- Allow DHCP only within the local broadcast domain/VLAN or the specific relay path.
- Block inbound DHCP from untrusted segments to prevent rogue DHCP behavior.
Mail: SMTP 25, submission 587, and 465
Mail has distinct flows: server-to-server delivery typically uses TCP/25, while user/app submission uses TCP/587 (and sometimes TCP/465). Hosting providers often restrict outbound TCP/25 to reduce spam; you may need to use a relay service or request an exception.
Practical rule patterns
- Inbound mail server (MX): allow inbound TCP/25 from the internet to your mail gateway.
- Outbound delivery: allow outbound TCP/25 from your mail server (or use a relay if blocked).
- App/user submission: allow inbound TCP/587 (and optionally 465) from your users/apps; enforce authentication and TLS.
Step-by-step: test SMTP connectivity
- Test if a remote host can reach your inbound 25:
nc -vz mail.example.com 25 - Test submission port:
nc -vz mail.example.com 587 - From your server, test outbound 25 (common cloud failure point):
nc -vz gmail-smtp-in.l.google.com 25
Databases: 3306 (MySQL) and 5432 (PostgreSQL)
Database ports are frequently targeted and should not be open to the internet in typical hosting. The common pattern is: database listens on a private IP, inbound allowed only from application servers (or a private subnet/security group), and outbound restricted as needed.
Practical rule patterns
- MySQL: allow inbound TCP/3306 only from app servers’ private IP range or security group.
- PostgreSQL: allow inbound TCP/5432 only from app servers’ private IP range or security group.
- Block public inbound to 3306/5432 unless you have a very specific, well-justified design (and then enforce VPN, IP allowlists, and strong auth).
Step-by-step: verify DB exposure is private
- From an internet host, confirm the DB port is not reachable:
nc -vz your-public-ip 3306 nc -vz your-public-ip 5432 - From an app server in the allowed network, confirm it is reachable:
nc -vz db-private-ip 3306 nc -vz db-private-ip 5432 - On the DB host, confirm it’s listening on the intended interface (private only):
ss -tlnp | egrep ':(3306|5432)\b'
ICMP for diagnostics (and why blocking it can hurt)
ICMP is used for reachability tests (ping) and for network error signaling. In hosting, allowing limited ICMP can speed troubleshooting and can be necessary for correct path MTU discovery (PMTUD). Over-blocking ICMP can lead to “it connects but hangs” symptoms, especially with VPNs, tunnels, or certain TLS payload sizes.
Practical rule patterns
- Allow inbound ICMP echo-request selectively (e.g., from monitoring systems or admin IPs) if you don’t want public ping.
- Allow essential ICMP error messages (often handled implicitly by platforms, but be cautious with blanket ICMP drops on host firewalls).
Ephemeral ports: the hidden half of “it works”
When a client connects to a server’s well-known port (like 443), the client uses an ephemeral source port (a temporary high-numbered port). Return traffic goes back to that ephemeral port on the client. This is why outbound rules and state tracking matter: even if you “only opened 443,” the connection still relies on ephemeral ports on the client side and on the firewall’s ability to track the session.
What to remember in hosting
- Servers: typically listen on well-known ports (80/443/22/etc.).
- Clients (browsers, app servers making outbound calls): use ephemeral ports as the source; they need outbound allowed and return traffic permitted.
- Common ephemeral ranges: varies by OS (often 32768–60999 or 49152–65535). You rarely open these inbound on servers; stateful devices handle return traffic automatically.
Inbound vs outbound rules, and stateful security groups
Cloud security groups and many firewalls are stateful: if you allow an outbound connection, the return traffic is automatically allowed back in (and vice versa for inbound-initiated sessions), without needing an explicit rule for the ephemeral return path. In contrast, stateless filtering (common in some network ACLs) requires you to explicitly allow both directions.
Practical implications
- If your web server allows inbound TCP/443 in a stateful security group, you typically do not need to open inbound ephemeral ports for responses.
- If you use stateless ACLs, you must allow return traffic explicitly (often “ephemeral port range” back to clients, plus the service port inbound).
- Outbound restrictions can break “server as a client” behaviors: package updates (HTTP/HTTPS), calling external APIs (443), sending mail (25/587), or DNS resolution (53).
Step-by-step: reason about a connection with rules
- Identify the listener (destination port on the server): e.g., TCP/443 on the web server.
- Identify the initiator: browser on the internet initiates to server:443 from client:ephemeral.
- Check inbound rules on the server side: allow TCP/443 from the client source range (often 0.0.0.0/0 for public web).
- Check outbound rules on the server side: usually allow established/related automatically (stateful) or allow outbound ephemeral responses (stateless design).
- If there is a load balancer, repeat the same logic at each hop (internet → LB, LB → instance).
Scenario drills (troubleshooting by symptoms)
Drill 1: Website not reachable on 443 but works on 80
Symptom: http:// loads (or at least connects), but https:// times out or fails to connect.
Goal: determine whether it’s a network rule issue or an application/listener/certificate issue.
- Confirm port reachability from outside:
nc -vz yourdomain.example 80 nc -vz yourdomain.example 443 - If 443 is not reachable (timeout/filtered): check inbound rules at the public edge (security group/firewall/load balancer listener). Ensure TCP/443 is allowed from the internet to the correct target.
- If 443 is reachable but HTTPS fails (connection but TLS error): check that the service is actually listening on 443 and has a valid certificate configured. On the server:
ss -tlnp | grep ':443' - If using a load balancer: verify the LB has a 443 listener and forwards to the correct backend port, and that backend security rules allow traffic from the LB (not necessarily from the whole internet).
- Check redirect behavior: if you expect 80 to redirect to 443, verify:
curl -I http://yourdomain.example/
Drill 2: SSH reachable only from certain IPs
Symptom: SSH works from the office/VPN but not from home (or vice versa).
Goal: confirm the restriction is intentional and correctly scoped, and identify mismatched source IP assumptions.
- Find your current public IP from the client network you’re testing (use any trusted “what is my IP” method).
- Compare to the allowlist in the inbound rule for TCP/22. If your IP changed (common with residential ISPs), SSH will fail by design.
- Validate the failure mode: a timeout usually indicates filtering; “connection refused” suggests the port is reachable but the SSH service isn’t listening.
- Use a bastion/VPN pattern if your admin IPs are not stable: allow 22 only from the bastion/VPN egress, then hop internally.
Drill 3: DNS queries failing due to blocked UDP or TCP fallback
Symptom: some DNS lookups fail intermittently; small queries might work but others fail, or zone transfers fail.
Goal: determine whether UDP/53, TCP/53, or both are blocked along the path.
- Test UDP DNS:
dig @resolver-or-ns example.com A - Test TCP DNS explicitly:
dig +tcp @resolver-or-ns example.com A - Interpret results:
- If UDP fails but TCP works: UDP/53 is blocked; most clients will struggle.
- If UDP works but TCP fails: large responses, DNSSEC, and zone transfers can fail; fix TCP/53 rules (often forgotten).
- If both fail: the resolver/nameserver may be down, misrouted, or blocked entirely.
- Fix the rules: ensure inbound allows match the server role (public authoritative vs internal resolver) and include both UDP/53 and TCP/53 where appropriate.