Scenario / Questions

I have Googled about a solution for quite some time, but couldn’t find an answer.

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 assign required privileges to the current user to access port 80.

Find below all possible solutions or suggestions for the above questions..

Suggestion: 1

Short answer: you can’t. Ports below 1024 can be opened only by root. As per comment – well, you can, using CAP_NET_BIND_SERVICE, but that approach, applied to java bin will make any java program to be run with this setting, which is undesirable, if not a security risk.

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

Suggestion: 2

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 …

Suggestion: 3

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

Suggestion: 4

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

Suggestion: 5

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;
        }
}

Suggestion: 6

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

Suggestion: 7

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.

Suggestion: 8

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 🙂

Suggestion: 9

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

Suggestion: 10

You can use redir program:

sudo redir --lport=80 --laddr=192.168.0.101 --cport 9990 --caddr=127.0.0.1

Suggestion: 11

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)

Suggestion: 12

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

Suggestion: 13

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.

Suggestion: 14

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.

Suggestion: 15

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.

Suggestion: 16

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

Suggestion: 17

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.

Suggestion: 18

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.

Suggestion: 19

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.

Suggestion: 20

Necromancing.

Simple. With a normal or old kernel, you don’t.
As pointed out by others, iptables can forward a port.
As also pointed out by others, CAP_NET_BIND_SERVICE can also do the job.
Of course CAP_NET_BIND_SERVICE will fail if you launch your program from a script, unless you set the cap on the shell interpreter, which is pointless, you could just as well run your service as root…
e.g. for Java, you have to apply it to the JAVA JVM

sudo /sbin/setcap 'cap_net_bind_service=ep' /usr/lib/jvm/java-8-openjdk/jre/bin/java

Obviously, that then means any Java program can bind system ports.
Dito for mono/.NET.

I’m also pretty sure xinetd isn’t the best of ideas.
But since both methods are hacks, why not just lift the limit by lifting the restriction ?
Nobody said you have to run a normal kernel, so you can just run your own.

You just download the source for the latest kernel (or the same you currently have).
Afterwards, you go to:

/usr/src/linux-<version_number>/include/net/sock.h:

There you look for this line

/* Sockets 0-1023 can't be bound to unless you are superuser */
#define PROT_SOCK       1024

and change it to

#define PROT_SOCK 0

if you don’t want to have an insecure ssh situation, you alter it to this:
#define PROT_SOCK 24

Generally, I’d use the lowest setting that you need, e.g 79 for http, or 24 when using SMTP on port 25.

That’s already all.
Compile the kernel, and install it.
Reboot.
Finished – that stupid limit is GONE, and that also works for scripts.

Here’s how you compile a kernel:

https://help.ubuntu.com/community/Kernel/Compile

# You can get the kernel-source via package linux-source, no manual download required
apt-get install linux-source fakeroot

mkdir ~/src
cd ~/src
tar xjvf /usr/src/linux-source-<version>.tar.bz2
cd linux-source-<version>

# Apply the changes to PROT_SOCK define in /include/net/sock.h

# Copy the kernel config file you are currently using
cp -vi /boot/config-`uname -r` .config

# Install ncurses libary, if you want to run menuconfig
apt-get install libncurses5 libncurses5-dev

# Run menuconfig (optional)
make menuconfig

# Define the number of threads you wanna use when compiling (should be <number CPU cores> - 1), e.g. for quad-core
export CONCURRENCY_LEVEL=3
# Now compile the custom kernel
fakeroot make-kpkg --initrd --append-to-version=custom kernel-image kernel-headers

# And wait a long long time

cd ..

In a nutshell, use iptables if you want to stay secure, compile the kernel if you want to be sure this restriction never bothers you again.