How to Resolve EACCES Error When Running Node.js on Port 80 in Linux


2 views

When attempting to run a Node.js application on port 80, developers often encounter the frustrating EACCES error. This isn't necessarily because the port is occupied - as your netstat output shows no process listening on port 80 - but rather due to Linux's security measures.

The key error message is:

Error: listen EACCES
    at errnoException (net.js:904:11)

In Unix-like systems, ports below 1024 are considered "privileged ports" and require root access. This is a security feature preventing regular users from running services on these standard ports.

1. Running Node as Root (Not Recommended)

While simplest, running Node with root privileges poses security risks:

sudo node app.js

2. Using Port Forwarding with Authbind

A safer alternative is configuring authbind to allow your user account to bind to low ports:

sudo apt-get install authbind
sudo touch /etc/authbind/byport/80
sudo chown youruser:youruser /etc/authbind/byport/80
sudo chmod 755 /etc/authbind/byport/80

Then run your app with:

authbind --deep node app.js

3. Reverse Proxy with Nginx (Recommended)

The most robust solution is using Nginx as a reverse proxy:

server {
    listen 80;
    server_name yourdomain.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

To thoroughly check for port conflicts:

sudo lsof -i :80
sudo netstat -tulnp | grep :80
sudo ss -tulnp | grep :80

On cloud instances, check security groups/iptables:

sudo iptables -L -n -v
sudo ufw status

If you must use port 80 temporarily for testing, you can forward it:

sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 3000

For production deployments with port 80 access:

[Unit]
Description=Node.js Service
After=network.target

[Service]
ExecStart=/usr/bin/node /path/to/your/app.js
User=root
Group=root
Restart=always

[Install]
WantedBy=multi-user.target

The error Error: listen EACCES you're encountering is a permission-related issue when trying to bind Node.js to port 80. This is fundamentally a Linux security feature - ports below 1024 are considered privileged ports that require root access.

// Typical error output
events.js:72
    throw er; // Unhandled 'error' event
          ^
Error: listen EACCES
    at errnoException (net.js:904:11)
    at Server._listen2 (net.js:1023:19)

Your netstat -an output shows no service listening on port 80, but let's verify thoroughly:

// Check all processes using port 80
sudo lsof -i :80

// Alternative command showing process IDs
sudo ss -tulnp | grep ':80'

If these commands return empty, it confirms port 80 isn't being blocked by another process but rather by system permissions.

Option 1: Run Node as Root (Not Recommended)

While technically possible, running Node.js with root privileges poses security risks:

sudo node app.js  // Not recommended for production

Option 2: Port Forwarding with iptables

A safer approach is to run Node on a high port and forward:

// Run your app on port 3000
const port = process.env.PORT || 3000;
app.listen(port);

// Then set up forwarding (run as root)
sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3000
sudo iptables-save > /etc/iptables.rules

Option 3: Use authbind (Recommended)

authbind allows specific users to bind to privileged ports:

// Install authbind
sudo apt-get install authbind

// Configure for port 80
sudo touch /etc/authbind/byport/80
sudo chown youruser:youruser /etc/authbind/byport/80
sudo chmod 755 /etc/authbind/byport/80

// Run your app
authbind --deep node app.js

Option 4: Reverse Proxy with Nginx

The most production-ready solution:

// Sample nginx configuration
server {
    listen 80;
    server_name yourdomain.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

After implementing any solution, verify it works:

curl -I http://localhost
netstat -tulnp | grep -E '80|3000'

Remember to:

  • Configure your firewall to allow port 80 traffic
  • Consider using HTTPS (port 443) for production
  • Use process managers like PM2 for Node.js applications