57

I want to run a web server on my Mac as a non-root process. Normally only root processes can bind to port 80 (or to any port below 1024).

Can I open port 80 specifically so that non-root processes can listen on it?

Avner
  • 673

6 Answers6

29

This is difficult to do by design, and unless you have root access to your machine none of the following will work as they require root to setup the changes. Once changed, though, userspace programs will have access without having root.

There are two common ways to accomplish this, and which you choose will depend on why you're trying to work around the restriction:

Point port 80 to another port, such as 8080

By reconfiguring your machine to pass all port 80 traffic to port 8080, or any port of your choosing, then you can allow user space servers to receive root privilege ports in the area they are given access to.

The process is straightforward:

Step 1: View current firewall rules.

sudo ipfw show

Step 2: Add port forwarding rule (80 to 8080)

sudo ipfw add 100 fwd 127.0.0.1,8080 tcp from any to any 80 in

If you want to remove your firewall rules run:

sudo ipfw flush

(source)

This is a temporary change, and will revert once you reboot, or flush as indicated int he last line.

You can make the change permanent, or you could add the command as a startup line prior to starting your server, which is probably safer from the standpoint of security.

Use Authbind

Authbind was designed specifically to allow one program access to lower level ports without giving it full root access.

There is a MacOSX port:

https://github.com/Castaglia/MacOSX-authbind

It may still be limited to IPv4 traffic, though, so you may have to do some additional investigation to find if it meets your needs

Adam Davis
  • 8,943
  • LOVE MacOSX-authbind... It lets you run, for example, a web server on port 80 - as a "regular Administrator". i.e. in your launchd .plist... "ProgramArguments": [ "path/to/authbind", "/usr/bin/php", "-c", "/www/.router.ini", "-S", "0.0.0.0:80", "-t", "/www", "/www/.router.php"]` Woohoo! – alex gray May 27 '14 at 18:22
  • 15
    OS X Yosemite removes ipfw. This gist describes an alternative solution using pf. – lyschoening Oct 17 '14 at 14:31
  • Note that redirecting traffic to unprivileged port can be insecure if you're on a shared environment; another process may bind to that port before your program does or if your program unbind the port even momentarily for a quick restart. – Lie Ryan Aug 28 '15 at 15:02
  • ipfw is not available in current version of macOS and the gist for using pf as an alternative was deleted. Therefore, as it stands, this answer is no as useful. – vhs Nov 28 '20 at 02:53
  • The gist was deleted, but the Internet Archive knows all. https://web.archive.org/web/20181219143818/https://gist.github.com/zhoutong/8adca7038639f0f5fb0e – Wowfunhappy Mar 31 '21 at 23:26
  • ipfw is the right answer, but it's named pf on macos; I posted an answer that works on macOS 14: https://apple.stackexchange.com/a/467165/191316 – cpurdy Dec 07 '23 at 21:16
10

You can use ncat to forward traffic from a web server running on some other port:

sudo ncat -l -p 80 -c ' ncat -l -p 1234'

This will forward traffic on port 80 to localhost:1234. This is a bit of a kludge however, I wouldn't use it anywhere beyond quick testing and definitely not in production.

Note that this won't allow a non-root process to bind to it, but by picking a port the process can bind to, 1234 in this example, it will look like it is bound to port 80. This is doing the equivalent of forwarding port 80 to port 1234 with a firewall, but on a far more temporary basis.

Mathew Hall
  • 1,116
2

You can also use ssh to do port forwarding. So if you have a server running on 8080, you can forward traffic from port 80. Here is a script I use, which stops native apache if it's running and forwards traffic:

forward8080to80.command:

echo "You may close this terminal and the forwarding will continue."
echo "To stop, kill the ssh process found by `sudo lsof -i ':80' | grep LISTEN`"
sudo apachectl stop
sudo ssh user@127.0.0.1 -L 80:127.0.0.1:8080
bdombro
  • 121
  • Ssh port forwarding can be quite low performance, and the security features don't make a lot of sense in a local->local environment. Better to use osx's built in port forwarding, or something like ncat. – Shayne Jan 09 '17 at 05:09
0

The setuid method is the only thing I found that works on OS X Catalina (10.15). For example, to run npm run serve --port 80 effectively, you would run sudo chmod u+s $(which npm).

datico
  • 101
0

As of macOS 14 (14.1 to be more specific, although this has been around for a few releases), you can use BSD's pf (packet filter) command, which is part of macOS (macOS is based on FreeBSD).

For example, to use port 80 and 443 by redirecting them locally to port 8080 and 8090 respectively, you can create a port-forwarding.conf file with the following contents:

rdr pass on lo0 inet proto tcp from any to self port 80  -> 127.0.0.1 port 8080
rdr pass on lo0 inet proto tcp from any to self port 443 -> 127.0.0.1 port 8090

(Note that the lo0 is redirecting the localhost interface; you may have to alter that depending on your use case.)

Then you can apply those settings:

sudo pfctl -evf port-forwarding.conf

Now your program can bind to 8080 and 8090 instead of binding to 80 and 443, but traffic coming on the specified interface at 80 and 443 will be locally routed to the listeners on 8080 and 8090.

cpurdy
  • 101
-3

What you should be able to do is open port 80 on your router and point it to the local IP address of your web server. Then on your Mac, enable Web Sharing from the System Preferences>Sharing preference pane and point it to the directory of your choosing. This has worked for me in the past until switched over to 10.6 Server.

Matt Love
  • 6,403
  • 1
    I'm looking for this as a solution for my own dev machine. Since I have to work at places where I don't have control over the router, this solution could not work for me. I suspect it should work if you're setting up a server and for some reason do not have root access. – Avner Jan 18 '12 at 22:55
  • So, just to be clear, you're trying to set up a web server at different client sites, but don't have the access to open port 80? How will you get the port open on the router if you don't have access? Am I understanding correctly or am I way off base? – Matt Love Jan 18 '12 at 23:01
  • I'm just trying to use port 80 on my own development machine not on a production server. I deploy on heroku anyway. – Avner Jan 18 '12 at 23:07