I'd like to accept connections briefly for development when I'm NATed, and so I'm attempting to do this:

$ ssh ubuntu@example.org -R 80:localhost:80

Which fails as I'm trying to bind a port that is to low:

Warning: remote port forwarding failed for listen port 80

So I've discovered that I can do setcap 'cap_net_bind_service=+ep' /my/application to allow it to listen to ports lower than 1024. So I've got this in my suders crontab:

@reboot setcap 'cap_net_bind_service=+ep' /usr/sbin/sshd

But it's still not letting me bind on port 80. What am I doing wrong? I'm just going to use nginx to proxy to 8080 or iptables or something instead, but I'm still curious why what I was trying to do didn't work.

  • What filesystem are you using? Not all filesystems support setcap. – Gilles Jun 24 '12 at 1:20
  • @Gilles I'm using ext4, it's the default Ubuntu image off AWS and I haven't done anything fancy with it. – Kit Sunde Jun 24 '12 at 7:03
  • It sounds as if you are root on the box. Maybe I'm ignorant but shouldn't just executing the first line as root solve your problem? – Christian Jun 25 '12 at 7:26
  • @Christian You can't bind on <1024 without sudo by design. Like how you cannot apt-get install foo without first doing sudo. – Kit Sunde Jun 25 '12 at 8:23
  • @KitSunde Yeah, root is an un-Ubuntuic way of saying sudo. It's a user that has all the privileges that a normal user only gets when doing sudo. root is also sometimes called the superuser. So basically my question to you was: You seem to be able to do sudo on the box, why can't you in this case? – Christian Jun 25 '12 at 12:14

OpenSSH will flat-out refuse to bind to privileged ports unless the user id of the logged in user is 0 (root). The relevant lines of code are:

if (!options.allow_tcp_forwarding ||
    no_port_forwarding_flag ||
    (!want_reply && listen_port == 0) ||
    (listen_port != 0 && listen_port < IPPORT_RESERVED &&
    pw->pw_uid != 0)) {
        success = 0;
        packet_send_debug("Server has disabled port forwarding.");

Source: http://www.openssh.com/cgi-bin/cvsweb/src/usr.bin/ssh/serverloop.c?annotate=1.162 lines 1092-1098

If you're curious, pw is of type struct passwd * and on linux is defined in /usr/include/pwd.h

  • Oh I wasn't expecting that, this most certainly would answer my question. – Kit Sunde Jul 30 '12 at 15:29

I meet the similar problem, so the solution I ended up is to add DNAT rule to the OUTPUT chain of nat table:

iptables -t nat -A OUTPUT -d -p tcp --dport 80 \
-j DNAT --to-destination :8080

This rule effectively replaces the destination port 80 with 8080 for all locally generated tcp packets.

If you wish to allow any incoming connections to be forwarded as well then add one extra rule to the PREROUTING nat chain:

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

where is the IP address of the interface that should be forwarding incoming connections to your web service


You could also just add your public key to the /root/.ssh/authorized_keys list. If you are paranoid then you will want to prohibit running of any commands as root like:

no-pty,no-agent-forwarding,no-X11-forwarding,command="/bin/noshell" ssh-rsa YOUR_PUBLIC_KEY 

Note that logging in as root may require adding "PermitRootLogin without-password" in /etc/ssh/sshd_config.


From the client end, you can run ssh via sudo:

sudo ssh -L 80: myuser@myhost.com

It works, although I'm admittedly not sure about the security implications for your local system.

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.