html
When Nginx works locally but fails on external IP connections, we're typically dealing with one of these layers:
- Network configuration (firewalls, routing)
- Nginx binding configuration
- OS-level network restrictions
Before diving into solutions, let's verify some critical components:
# Check if Nginx is listening on all interfaces (0.0.0.0)
sudo netstat -tulnp | grep nginx
# Expected output showing 0.0.0.0:81
tcp 0 0 0.0.0.0:81 0.0.0.0:* LISTEN 1234/nginx: worker
1. Nginx Binding Configuration
Your current configuration only implies IPv4 binding. Explicitly specify the interface:
server {
listen 81 default_server;
listen [::]:81 default_server; # IPv6
server_name _;
# ... rest of config
}
2. Ubuntu UFW Deep Dive
While you've opened port 81, let's ensure it's properly configured:
# Verify UFW status
sudo ufw status verbose
# If port 81 isn't listed:
sudo ufw allow 81/tcp
# For more granular control if you have specific IP restrictions:
sudo ufw allow from 192.168.1.0/24 to any port 81
3. Kernel-Level Firewalls
For systems using iptables (common in cloud environments):
# Check current rules
sudo iptables -L -n -v
# Add rule if missing
sudo iptables -A INPUT -p tcp --dport 81 -j ACCEPT
# Persist rules (Ubuntu)
sudo netfilter-persistent save
4. Cloud Provider Gotchas
If running on AWS/GCP/Azure, remember:
- Security groups must allow inbound traffic
- Network ACLs might block the port
- Some providers require instance-level configuration
When basic fixes don't work, try these diagnostic tools:
# Check if port is open from external perspective
nc -zv your_server_ip 81
# Check for dropped packets
sudo dmesg | grep dropped
# Full network path verification
traceroute your_server_ip
mtr your_server_ip
Here's a complete working configuration for external access:
server {
listen 81 default_server;
listen [::]:81 default_server ipv6only=on;
server_name yourdomain.com;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ =404;
}
}
When Nginx responds locally but refuses external connections on a custom port (81 in this case), we're typically dealing with one of three fundamental issues:
# Test local connectivity (should succeed)
curl -I http://127.0.0.1:81
# Test external connectivity (fails with connection refused)
curl -I http://109.123.x.x:81
First, verify if the port is actually open to external traffic:
# Check listening ports and bound addresses
ss -tulnp | grep :81
# Expected output if properly bound:
# tcp LISTEN 0 511 *:81 *:* users:(("nginx",pid=1234,fd=6))
# If you see 127.0.0.1:81 instead of *:81, that's the problem
The default configuration only binds to IPv4 without explicit external binding. Modify your server block:
server {
listen 81 default_server; # Explicit default server for all IPv4
listen [::]:81 default_server; # IPv6 if needed
# Alternative explicit binding:
# listen 109.123.x.x:81;
server_name _; # Wildcard or your actual domain
# Rest of your configuration
location / {
try_files $uri $uri/ /index.html;
}
}
UFW might not be the only firewall in play. Consider these checks:
# Check UFW status
sudo ufw status verbose
# Check iptables directly (UFW is a frontend)
sudo iptables -L -n -v | grep 81
# If using cloud providers, check security groups:
# AWS Security Groups, GCP Firewall Rules, etc.
Linux kernel parameters might block the connection:
# Check if SYN packets are reaching your server
sudo tcpdump -i eth0 'tcp port 81 and tcp[tcpflags] & (tcp-syn) != 0'
# Verify sysctl settings
sysctl net.ipv4.conf.all.route_localnet
sysctl net.ipv4.ip_forward
- Verify Nginx binds to 0.0.0.0:81 (not just 127.0.0.1)
- Confirm UFW allows port 81/tcp from desired networks
- Check cloud provider network ACLs
- Test with simple netcat listener:
nc -l 81
- Inspect Nginx error logs:
tail -f /var/log/nginx/error.log