I need to run a certain application on a CentOS 7.5 based system. This application needs to bind to port 389 in order to expose a ldap service. This application is run by SystemD but fails to start because the user I have to use for running the app is not allowed to bind to ports lower than 1024. I already tried to setcap 'cap_net_bind_service=+ep' /opt/jdk8/bin/java but after this Java is not even able to start.

I've already seen solutions based on iptables forward, ssh tunnels etcetera. All of this "magic" is not allowed on the system I have to use. I guess the same applies to setcap.

Is there some setting I can use within SystemD ? I am sure it can somehow be done because I have to run nginx on port 80 with the same user and there it works.

As I don't have the sourcecode of the application I can not change the way it opens the port.

  • I normally just use sudo is that also not an option? – jesse_b Jul 5 '18 at 14:07
  • @Jesse_b: Can you please be more specific ? Is this a setting I could use within the SystemD service definition ? A normal sudo /opt/jdk/bin/java -jar foo.jar does not do the job – Marged Jul 5 '18 at 14:17
  • Related - stackoverflow.com/questions/413807/…. Shows many methods. – slm Jul 5 '18 at 14:18

If you could give java (or anything that uses dynamic libraries) elevated capabilities, then an attacker could switch the libraries, to gain capabilities.

A solution

Write a minimal C program (statically linked), have it open the port, and attach it to file descriptor 3. And then exec the java program. The java program will have to do an fdopen, to make it look like a file from java's point of view (open "/dev/fd/3") This wrapper would need the capabilities.

  • I guess this is what nginx does. I would be able to code in C or golang, but I would prefer an approach which only involves SystemD native settings. Unfortunately I can not change the code of the application. – Marged Jul 5 '18 at 14:11

There are many solutions that you can enlist here, since you're using systemd this would seem to be the way to go, using ListenStream:

$ cat /etc/systemd/system/gitea.socket
Description=Gitea socket


And then once you've defined your .socket file define your unit file like so using it:

Description=Gitea (Git with a cup of tea)

ExecStart=/home/git/go/src/code.gitea.io/gitea/gitea web
Environment=USER=git HOME=/home/git



  • 1
    I did this (added the myapp.socket, changed to ListenStream=389, added Requires and After) and systemctl daemon-reloaded. But when I systemctl start myapp I still get a Caused by: java.net.SocketException: Permission denied error. – Marged Jul 6 '18 at 9:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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