When attempting to bind Tomcat to port 80 on Ubuntu, you'll encounter the classic error:
java.net.BindException: Permission denied <null>:80
This occurs because ports below 1024 are privileged ports in Linux, requiring root access. Your security-conscious instinct is correct - running Tomcat as root is dangerous.
1. Authbind Method (Recommended)
Authbind allows specific users to bind to privileged ports:
sudo apt-get install authbind
sudo touch /etc/authbind/byport/80
sudo chmod 500 /etc/authbind/byport/80
sudo chown tomcat7 /etc/authbind/byport/80
Then modify your Tomcat startup script (usually in /etc/default/tomcat7
):
AUTHBIND=yes
2. IPTables Port Forwarding
Redirect traffic from port 80 to your Tomcat port (8080):
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
sudo iptables-save > /etc/iptables.rules
Make it persistent across reboots by adding to /etc/network/interfaces
:
pre-up iptables-restore < /etc/iptables.rules
3. Systemd Socket Activation
For Ubuntu 16.04+ with systemd:
# Create /etc/systemd/system/tomcat.socket
[Unit]
Description=Tomcat Socket
[Socket]
ListenStream=80
[Install]
WantedBy=sockets.target
Then create /etc/systemd/system/tomcat.service
:
[Unit]
Requires=tomcat.socket
After=network.target
[Service]
User=tomcat
Group=tomcat
WorkingDirectory=/usr/share/tomcat
Environment=CATALINA_PID=/var/run/tomcat.pid
ExecStart=/usr/share/tomcat/bin/catalina.sh run
Remember to:
- Configure your Security Group to allow inbound traffic on port 80
- Verify no NACL is blocking the traffic
- Check that your instance has a public IP or Elastic IP
If it still doesn't work:
# Check listening ports
sudo netstat -tulpn | grep :80
# Verify AWS Security Groups
aws ec2 describe-security-groups --group-ids sg-xxxxxxxx
# Test connectivity
telnet your-ip 80
The authbind method is generally the cleanest solution that maintains security while solving the port binding issue.
The key error in your Catalina.out reveals everything:
java.net.BindException: Permission denied <null>:80
at org.apache.tomcat.util.net.JIoEndpoint.bind(JIoEndpoint.java:391)
This occurs because ports below 1024 are privileged ports in Linux, requiring root access. Your Tomcat instance (running as non-root user) cannot bind to port 80 directly.
Authbind allows specific users/programs to bind to low-numbered ports:
# Install authbind
sudo apt-get install authbind
# Configure for port 80
sudo touch /etc/authbind/byport/80
sudo chmod 500 /etc/authbind/byport/80
sudo chown tomcat7 /etc/authbind/byport/80 # Replace with your Tomcat user
# Modify Tomcat startup script
sudo nano /etc/default/tomcat7
Add this line at the end:
AUTHBIND=yes
Redirect traffic from port 80 to 8080:
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
sudo iptables-save | sudo tee /etc/iptables.rules
Make it persistent after reboot by adding to /etc/rc.local
:
iptables-restore < /etc/iptables.rules
Create a new systemd socket file:
sudo nano /etc/systemd/system/tomcat80.socket
With this content:
[Unit]
Description=Tomcat Socket for Port 80
[Socket]
ListenStream=80
BindIPv6Only=both
Accept=yes
[Install]
WantedBy=sockets.target
Then create a service file:
sudo nano /etc/systemd/system/tomcat80@.service
With this content:
[Unit]
Description=Tomcat on Port 80
[Service]
Type=simple
ExecStart=/usr/share/tomcat8/bin/catalina.sh run
User=tomcat8
Group=tomcat8
After implementing any solution, verify with:
sudo netstat -tulnp | grep 80
curl -I http://localhost
Never run Tomcat as root. Instead:
- Use authbind for temporary solutions
- Implement proper firewall rules
- Consider using a reverse proxy (Nginx/Apache)
For production environments, I recommend combining authbind with proper SELinux/AppArmor configurations.