Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I have googled about it for quite some time, but couldn't find it.

I am on Ubuntu Linux and want to run a server on port 80, but due to security mechanism of Ubuntu, I get the following error:

java.net.BindException: Permission denied:80

I think it should be simple enough to either disable this security mechanism so that port 80 is available to all users, or to give necessary privilege to the current user to access port 80; but shame on me, can't figure that out.

share|improve this question

migrated from stackoverflow.com Feb 14 '10 at 20:47

This question came from our site for professional and enthusiast programmers.

2  
What is the problem to run the server on another port that is unprivileged? You are thinking about something as harsh as disabling the security mechanism without providing at least a very serious reason for running a server on that port. Is the server hardcoded to bind to port 80? If so, throw it away. –  Anonymous Feb 20 '10 at 17:00
    
Or a Python error message: socket.error: [Errno 13] Permission denied –  Kazark Nov 15 '11 at 15:15
3  
possible duplicate of Regular user using ports below 1024 –  Roman Jul 7 '13 at 13:19
1  
You can't. Ports below 1024 are privileged and only root can open listening sockets on them. The appropriate thing to do is to drop permissions after opening it. –  Falcon Momot Jul 7 '13 at 17:38
1  
"Anonymous" - the users in the world have been trained to look for certain services at certain ports. In some instances, its been standardized. For example, HTTP on port 80 and HTTPS on port 443. Its kind of hard to change the users and standards of the world. –  noloader Feb 2 at 9:25
add comment

19 Answers 19

Short answer: you can't. Ports below 1024 can be opened only by root.

The long answer: you can redirect connections on port 80 to some other port you can open as normal user.

Run as root:

# iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

As loopback devices (like localhost) do not use the prerouting rules, if you need to use localhost, etc., add this rule as well (thanks @Francesco):

# iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 8080

NOTE: The above solution is not well suited for multi-user systems, as any user can open port 8080 (or any other high port you decide to use), thus intercepting the traffic. (Credits to CesarB).

EDIT: as per comment question - to delete the above rule:

# iptables -t nat --line-numbers -n -L

This will output something like:

Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination         
1    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:8080 redir ports 8088
2    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:80 redir ports 8080

The rule you are interested in is nr. 2, so to delete it:

# iptables -t nat -D PREROUTING 2
share|improve this answer
    
I see others have posted faster than me. I'll leave my answer just for the iptables command line, but please, vote the other answers, not mine. –  Sunny Nov 10 '08 at 14:42
8  
@Sunny: upvotes are not for the fastest gun in the west, but for the best responses. Yours is the best so far (I only mentioned iptables; you actually provided the full command line). The only thing mine has yours doesn't is the caveat about other users also being able to bind to port 8080. –  CesarB Nov 10 '08 at 14:45
    
CesarB: anyway, you have your +1. –  Sunny Nov 10 '08 at 15:29
1  
Note that this doesn't work with IPv6. –  Emmanuel Bourg Apr 2 '12 at 12:12
    
Could anybody explain how I can remove this rule later when I want to? After running it, it works, but it's apparently not a "rule" because it doesn't show up when i do sudo iptables --list. I know what iptables is and does, but i've never really used it before this. –  Encoderer Apr 2 '12 at 18:31
show 7 more comments

Use authbind.

It even works with Java if you enable Java's IPv4-only stack. I use:

authbind --deep $JAVA_HOME/bin/java -Djava.net.preferIPv4Stack=true …
share|improve this answer
1  
thanks for this! –  jldupont Oct 9 '09 at 15:02
3  
If the server is Tomcat you can use authbind automatically by setting AUTHBIND=yes in /etc/default/tomcat6 –  Emmanuel Bourg Apr 2 '12 at 12:16
    
I couldn't get this to work on Ubuntu server with the default Java package... –  Ashley Steel Jun 20 '12 at 17:17
    
Me neither, any known solution? –  mark Aug 16 '12 at 10:10
    
@mark, Try creating a question and explain what you have tried. Authbind has been the default for Ubuntu/Debian Java applications for a long time. –  geocar Aug 19 '12 at 11:19
show 1 more comment

Traditionally on Unix, only root can bind to low ports (<1024).

The simplest way to work around this is to run your server on a high port (for instance, 8080) and use a simple iptables rule to forward the connections from port 80 to port 8080. Note that with this you lose the extra protection from the low ports; any user on your machine can bind to port 8080.

share|improve this answer
add comment

Another solution is to make your app setuid so that it can bind with port 80. As root, do the following

chown root ./myapp
chmod +S ./myapp

Keep in mind that doing this, unless it's done absolutely right, will expose you to potential security holes, because your app will be talking to the network, and will be running with full root priviledges. If you take this solution, you should look at the source code for Apache or Lighttpd or something similar, where they use the root privileges to open up the port, but then immediately give up those privs and "become" a lower privileged user so that a hijacker can't take over your whole computer.

Update: As seen in this question, it appears that Linux kernels since 2.6.24 have a new capability that allow you to mark an executable (but not a script, of course) as having the "CAP_NET_BIND_SERVICE" capability. If you install the debian package "libcap2-bin", you can do that by issuing the command

setcap 'cap_net_bind_service=+ep' /path/to/program
share|improve this answer
3  
That is the same as running as root, unless the app knows how to drop priviledges. –  CesarB Nov 10 '08 at 14:48
7  
This is dangerous. This means that any request will run as root. It's for a reason that even apache starts as root to bind, and then drops the privileges to another user. –  Sunny Nov 10 '08 at 14:49
    
Subverting the restrictions Unix has on binding to port 80 is dangerous, whether you do it with setuid or with iptables hackery. –  Paul Tomblin Nov 10 '08 at 14:53
5  
Paul: the iptables is not so dangerous, because even if the app is compromised, it will not expose the system on attacks, at least not with root privileges. Running the app as root is another story. –  Sunny Nov 10 '08 at 14:55
1  
lol, love how the accepted answer has a -15 –  Evan Teran Dec 17 '08 at 18:53
show 7 more comments

If your system supports it you could maybe use capabilities. See man capabilities, the one you need would be CAP_NET_BIND_SERVICE. No, I`ve never used them myself and I don't know if they really work :-)

share|improve this answer
    
they do work, I use CAP_NET_RAW to run tools like tcpdump as a normal user. –  Justin Feb 15 '10 at 0:32
add comment

Approach proposed by Sunny and CesarB:

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

works fine but it has a small drawback -- it does not prevent user from connecting directly to port 8080 instead of 80.

Consider the following scenario when this can be a problem.

Let's say we have a server which accepts HTTP connections on port 8080 and HTTPS connections on port 8181.

We use iptables to establish the following redirections:

80  ---> 8080
443 ---> 8181

Now, let's suppose our server decides to redirect user from a HTTP page to a HTTPS page. Unless we carefully rewrite the response, it would redirect to https://host:8181/. At this point, we are screwed:

  • Some users would bookmark the https://host:8181/ URL and we would need to maintain this URL to avoid breaking their bookmarks.
  • Other users would not be able to connect because their proxy servers do not support non-standard SSL ports.

I use the following approach:

iptables -t mangle -A PREROUTING -p tcp --dport 80 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p tcp --dport 443 -j MARK --set-mark 1
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8181
iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -m mark --mark 1 -j ACCEPT
iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 8181 -m mark --mark 1 -j ACCEPT

Combined with default REJECT rule on the INPUT chain this approach prevents users from connecting directly to ports 8080, 8181

share|improve this answer
    
This is good, but why not just bind the daemon to localhost:8080 instead of 0.0.0.0:8080 ? I want to do that, but I need the iptables for that. –  Amala Dec 15 '11 at 17:20
add comment

Use a reverse proxy (nginx, apache+mod_proxy) or a caching reverse proxy (Squid, Varnish) in front of your application servers!

With a reverse proxy you can achieve a lot of interesting things like:

  • Load-balancing
  • Restarting your application servers with users receiving a fancy error page
  • Speed up things with cache
  • Fine-grained settings that you normally do with a reverse-proxy and not with an application server
share|improve this answer
add comment

If your system supports it you could maybe use capabilities. See man capabilities, the one you need would be CAP_NET_BIND_SERVICE.

On newer Debian/Ubuntu you can run:

sudo apt-get install libcap2-bin 
sudo setcap 'cap_net_bind_service=+ep' /path/to/program
share|improve this answer
add comment

I simply use Nginx in front. It can run on localhost too.

  • apt-get install nginx

.. or ..

  • pkg_add -r nginx

.. or what ever suits your OS.

All you need in nginx.conf, if running on localhost, is:

server {
        listen  80;
        server_name some.domain.org;
        location / {
            proxy_set_header    Host $host;
            proxy_set_header    X-Real-IP   $remote_addr;
            proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass  http://127.0.0.1:8081;
        }
}
share|improve this answer
    
I really like this solution. –  thomasfedb Dec 6 '12 at 16:05
    
This is (one of) the suggested solution from JFrog themselves: jfrog.com/confluence/display/RTF/nginx –  stolsvik Jan 1 at 23:27
add comment

Use sudo.

Configure sudo so that the regular user can run appropriate commands:

/etc/init.d/httpd start

Or

apachectl stop

Or

/usr/local/apache2/apachectl restart

Or

/myapp/myappbin start

(Or whatever other command/script you use to start/stop you particular webserver/app)

share|improve this answer
6  
This has the same issue -- running a service as root is a bad practice. –  Kevin Panko Sep 9 '09 at 18:44
add comment

With Linux, you have some two other options:

Both extensions to the Linux kernel allow to grant access rights on a very fine grained level. This would allow you to grant this process to open port 80 but it wouldn't inherit any of the other root rights.

From what I've heard, grsecurity is much more simple to use but SELinux is more secure.

share|improve this answer
add comment

You can use redir program:

sudo redir --lport=80 --laddr=192.168.0.101 --cport 9990 --caddr=127.0.0.1
share|improve this answer
add comment

One solution is to use iptables to perform PAT on packets for port 80. You can use this to route the packets to local port 8080, for example. Be sure and adjust the outgoing packets back to port 80.

In my experience the fine-grained permissions features of Linux are not compiled into standard kernels because of security issues.

share|improve this answer
add comment

If you are trying to do this so that a user-run command can use port 80, then your only solutions are the iptables tricks or setting the executable setuid-to-root.

The way something like Apache does this (it binds to port 80, but is running as someone other than root) is to run as root, bind to the port, then change the ownership of the process to the non-privileged user after the port is set up. If the app you are writing can be run by root, you can make it change owner to the non-priv user after the ports are set up. But if this is just for an average user to run from the command line, then you'll have to use one of the other solutions.

share|improve this answer
add comment

When I have various web serving applications (python scripts, tomcat engines, ...) that I don't want to run as root I usually configure an apache web server in front of them. Apache listens to port 80, and tomcat listens to 8080.

In apache:s config:

ProxyPass /webapp http://localhost:8080/webapp
ProxyPassReverse /webapp http://localhost:8080/webapp

See the mod-proxy documentation for more info: http://httpd.apache.org/docs/2.2/mod/mod_proxy.html

share|improve this answer
1  
The drawback of this solution is the loss of the incoming IP in the Tomcat logs. –  Emmanuel Bourg Apr 2 '12 at 12:22
add comment

I think the best solution is to sgid your app and as soon as it has its port bound it should drop the privileges by switching to another user.

share|improve this answer
add comment

As an aside, FreeBSD and Solaris (anyone remember that one?) let you do this (bind to low ports) without privilege escalation (ie, using programs to switch to root). Since you specified Linux, I'm just posting this as a notice to others that might find this question.

share|improve this answer
add comment

Some hostsystems are not allowing to use the NAT module, 'iptables' does not solve the problem in this case.

How about xinetd?

In my case (ubuntu 10.04)

# apt-get install xinetd
# touch /etc/xinetd.d/my_redirect
# vim /etc/xinetd.d/my_redirect

Paste the configuration:

service my_redirector_80
{
 disable = no
 socket_type = stream
 protocol = tcp
 user = root
 wait = no
 port = 80
 redirect = localhost 8080
 type = UNLISTED
}

Then:

# service xinetd restart

http://docs.codehaus.org/display/JETTY/port80 explains better.

share|improve this answer
    
This is basically equivalent to putting a reverse proxy in front of the server, but it's rather inefficient compared to dedicated solutions like HAproxy, Pound or Varnish that understand the HTTP protocol and can add useful headers likes X-Forwarded-For. –  Emmanuel Bourg Apr 2 '12 at 21:49
add comment

answer of sunny is correct, but you may face additional issues as loopback interface don't use the PREROUTING table,

so the iptables rules to add are two:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 8080
share|improve this answer
add comment

protected by Chris S Jan 2 at 4:46

Thank you for your interest in this question. Because it has attracted low-quality answers, posting an answer now requires 10 reputation on this site.

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.