Как запустить сервер на порту 80 как обычный пользователь в Linux?

311

Я уже давно гуглил о решении, но не смог найти ответ.

Я использую Ubuntu Linux и хочу запустить сервер на порту 80, но из-за механизма безопасности Ubuntu я получаю следующую ошибку:

java.net.BindException: в доступе отказано: 80

Я думаю, должно быть достаточно просто отключить этот механизм безопасности, чтобы порт 80 был доступен для всех пользователей, или назначить текущему пользователю необходимые привилегии для доступа к порту 80.

Дипак Миттал
источник
3
В чем проблема запустить сервер на другом порте, который не является привилегированным? Вы думаете о чем-то столь же резком, как отключение механизма безопасности без предоставления хотя бы очень серьезной причины для запуска сервера на этом порту. Сервер жестко привязан к порту 80? Если так, выбросьте это.
Аноним
4
Ты не можешь Порты ниже 1024 являются привилегированными, и только root может открывать для них сокеты прослушивания. Подходящее, что нужно сделать, - сбросить разрешения после его открытия.
Сокол Момот
2
«Аноним» - пользователи во всем мире обучены искать определенные сервисы в определенных портах. В некоторых случаях его стандартизировали. Например, HTTP на порте 80 и HTTPS на порте 443. Своего рода сложно изменить пользователей и стандарты мира.
1
@FalconMomot Если порты ниже 1024 являются привилегированными, почему серверу Apache не требуется один для ввода пароля для получения корневых привилегий на порту 80, и как они это делают? Я думаю, что спрашивающий хочет знать, как это сделать (независимо от того, используется ли он технически как root или нет). Не стесняйтесь сказать мне, если я ошибаюсь, Дипак Миттал.
Шуле

Ответы:

355

Краткий ответ: вы не можете. Порты ниже 1024 могут быть открыты только root. Что касается комментария - ну, вы можете, используя CAP_NET_BIND_SERVICE , но этот подход, примененный к java bin, приведет к запуску любой java-программы с этим параметром, что нежелательно, если не представляет угрозу безопасности.

Длинный ответ: вы можете перенаправить соединения через порт 80 на другой порт, который вы можете открыть как обычный пользователь.

Запустите с правами root:

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

Поскольку петлевые устройства (например, localhost) не используют правила предварительной маршрутизации, если вам нужно использовать localhost и т. Д., Добавьте также и это правило ( спасибо @Francesco ):

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

ПРИМЕЧАНИЕ. Приведенное выше решение не очень подходит для многопользовательских систем, поскольку любой пользователь может открыть порт 8080 (или любой другой порт высокого разрешения, который вы решите использовать), таким образом перехватывая трафик. (Кредиты для CesarB ).

РЕДАКТИРОВАТЬ: в соответствии с вопросом комментария - чтобы удалить вышеуказанное правило:

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

Это выведет что-то вроде:

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

Правило, которое вас интересует, это nr. 2, чтобы удалить его:

# iptables -t nat -D PREROUTING 2
Солнечно
источник
13
@Sunny: upvotes не для самого быстрого оружия на западе, но для лучших ответов. Ваш лучший пока (я упомянул только iptables; вы фактически предоставили полную командную строку). Единственное, чего у меня нет, это предостережение о том, что другие пользователи также могут связываться с портом 8080.
CesarB
3
Обратите внимание, что это не работает с IPv6.
Эммануэль Бур
3
Кто-нибудь может объяснить, как я могу удалить это правило позже, когда захочу? После запуска это работает, но это, очевидно, не «правило», потому что оно не появляется, когда я это делаю sudo iptables --list. Я знаю, что iptables и делает, но я никогда не использовал его до этого.
Кодировщик
4
Спасибо за ваш ответ ... всякий раз, когда я перезагружаю Ubuntu, это правило исчезает, и я должен запустить его снова. Есть ли способ сохранить его навсегда?
Кодерджи
4
@Coderji: проверьте раздел «сохранить» в документации сообщества: help.ubuntu.com/community/IptablesHowTo
Sunny
79

Используйте authbind .

Он даже работает с Java, если вы включите стек Java только для IPv4. Я использую:

authbind --deep $JAVA_HOME/bin/java -Djava.net.preferIPv4Stack=true …
geocar
источник
4
Если сервер Tomcat, вы можете использовать authbind автоматически, установив AUTHBIND=yesв / etc / default / tomcat6
Эммануэль Бург
Я не мог заставить это работать на сервере Ubuntu с пакетом Java по умолчанию ...
Эшли
Я тоже, какое-либо известное решение?
отметка
10
Обратите внимание, что вы должны настроить, authbindчтобы фактически позволить этому произойти. Со страницы man: «/ etc / authbind / byport / port проверяется. Если этот файл доступен для выполнения вызывающему пользователю, согласно access (2), то привязка к порту разрешена». Например, для порта 80 sudo touch /etc/authbind/byport/80 ; sudo chmod 777 /etc/authbind/byport/80. Первоначальная установка authbindобычно не имеет предварительно настроенных авторизаций.
Джейсон C
4
О, неонононононо, никогда не chmod 777 ничего!
Йоханнес
57

Если ваша система поддерживает это, вы можете использовать возможности. Посмотрите возможности человека, вам нужен CAP_NET_BIND_SERVICE.

В более новой версии Debian / Ubuntu вы можете запустить:

sudo apt-get install libcap2-bin 
sudo setcap 'cap_net_bind_service=+ep' /path/to/program
Отто Кекяляйнен
источник
это работает для nodejs: setcap 'cap_net_bind_service = + ep' / usr / bin / nodejs
JasonS
5
Этот. Интересно, почему этот ответ не имеет больше голосов. Гораздо проще, чем вариант iptables imho.
Доминик Р
5
это правильный и самый эффективный ответ, все остальные ответы приводят к снижению производительности или просто сомнительны / небезопасны.
OneOfOne
41

Другое решение - настроить приложение так, чтобы оно могло связываться с портом 80. От имени пользователя root выполните следующие действия.

chown root ./myapp
chmod +S ./myapp

Имейте в виду, что если вы сделаете это, если это не сделано абсолютно правильно, вы столкнетесь с потенциальными пробелами в безопасности, потому что ваше приложение будет общаться с сетью и будет работать с полными привилегиями суперпользователя. Если вы воспользуетесь этим решением, вам следует взглянуть на исходный код Apache или Lighttpd или чего-то подобного, где они используют привилегии root для открытия порта, но затем сразу же откажутся от этих привилегий и «станут» пользователями с более низкими привилегиями, чтобы угонщик не может захватить весь ваш компьютер.

Обновление: Как видно из этого вопроса , похоже, что ядра Linux начиная с 2.6.24 имеют новую возможность, позволяющую пометить исполняемый файл (но, конечно, не скрипт) как обладающий CAP_NET_BIND_SERVICEспособностью « ». Если вы устанавливаете пакет debian "libcap2-bin", вы можете сделать это, выполнив команду

setcap 'cap_net_bind_service=+ep' /path/to/program
Пол Томблин
источник
6
Это то же самое, что и запуск от имени пользователя root, если только приложение не знает, как удалить привилегии.
CesarB
14
Это опасно Это означает, что любой запрос будет выполняться от имени пользователя root. По какой-то причине даже apache запускается как root для привязки, а затем отбрасывает привилегии другому пользователю.
Солнечный
9
Пол: iptables не так опасен, потому что, даже если приложение взломано, оно не подвергнет систему атакам, по крайней мере, с правами root. Запуск приложения с правами root - другая история.
Солнечный
1
Опасность для iptables только в том случае, если это многопользовательская система, как сказал CesarB, поскольку любой может привязаться к 8080 и перехватить трафик.
Солнечный
1
LOL, любите, как принятый ответ имеет -15
Эван Теран
40

Я просто использую Nginx впереди. Он также может работать на локальном хосте.

  • apt-get install nginx

.. или же ..

  • pkg_add -r nginx

.. или то, что когда-либо подходит вашей ОС.

Все, что вам нужно в nginx.conf, если вы работаете на localhost, это:

сервер {
        слушай 80;
        имя_сервера some.domain.org;
        место нахождения / {
            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;
        }
}
CosmicB
источник
Мне очень нравится это решение.
thomasfedb
1
Это одно из предложенных решений от JFrog: jfrog.com/confluence/display/RTF/nginx
stolsvik
36

Подход, предложенный Sunny и CesarB:

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

работает нормально, но имеет небольшой недостаток - он не мешает пользователю подключаться напрямую к порту 8080 вместо 80.

Рассмотрим следующий сценарий, когда это может быть проблемой.

Допустим, у нас есть сервер, который принимает HTTP-соединения через порт 8080 и HTTPS-соединения через порт 8181.

Мы используем iptables для установки следующих перенаправлений:

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

Теперь предположим, что наш сервер решает перенаправить пользователя со страницы HTTP на страницу HTTPS. Если мы тщательно не перепишем ответ, он будет перенаправлен на https://host:8181/. На данный момент мы облажались:

  • Некоторые пользователи будут добавлять https://host:8181/URL в закладки, и нам нужно будет поддерживать этот URL, чтобы не сломать их закладки.
  • Другие пользователи не смогут подключиться, потому что их прокси-серверы не поддерживают нестандартные порты SSL.

Я использую следующий подход:

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

В сочетании с правилом REJECT по умолчанию в цепочке INPUT этот подход не позволяет пользователям напрямую подключаться к портам 8080, 8181.

Миша
источник
1
Это хорошо, но почему бы просто не привязать демона к localhost: 8080 вместо 0.0.0.0:8080? Я хочу сделать это, но мне нужны iptables для этого.
Amala
Это работает, действительно круто.
xtian
29

Традиционно в Unix только root может связываться с низкими портами (<1024).

Самый простой способ обойти это - запустить сервер на высоком порту (например, 8080) и использовать простое правило iptables для переадресации соединений с порта 80 на порт 8080. Обратите внимание, что при этом вы теряете дополнительную защиту от низкие порты; любой пользователь на вашей машине может подключиться к порту 8080.

CesarB
источник
23

Если ваша система поддерживает это, вы можете использовать возможности. Видишь man capabilities, тот, который тебе нужен CAP_NET_BIND_SERVICE. Нет, я никогда не использовал их сам и не знаю, действительно ли они работают :-)

WMR
источник
1
они работают, я использую CAP_NET_RAW для запуска таких инструментов, как tcpdump, как обычный пользователь.
Джастин
12

Используйте обратный прокси (nginx, apache + mod_proxy) или кеширующий обратный прокси (Squid, Varnish) перед своими серверами приложений!

С обратным прокси-сервером вы можете получить много интересных вещей, таких как:

  • Балансировки нагрузки
  • Перезапуск серверов приложений с пользователями, получающими причудливую страницу ошибок
  • Ускорьте работу с кешем
  • Детальные настройки, которые вы обычно делаете с обратным прокси, а не с сервером приложений
Джованни Торальдо
источник
6

Вы можете использовать программу redir:

sudo redir --lport=80 --laddr=192.168.0.101 --cport 9990 --caddr=127.0.0.1
user340994
источник
4

Используйте sudo.

Настройте sudo, чтобы обычный пользователь мог запускать соответствующие команды:

/etc/init.d/httpd start

Или же

apachectl stop

Или же

/usr/local/apache2/apachectl restart

Или же

/myapp/myappbin start

(Или любую другую команду / скрипт, который вы используете для запуска / остановки вашего конкретного веб-сервера / приложения)

Не сейчас
источник
8
Это имеет ту же проблему - запуск службы с правами root является плохой практикой.
Кевин Панко
4

Солнечный ответ правильный, но вы можете столкнуться с дополнительными проблемами, так как интерфейс обратной связи не использует таблицу PREROUTING,

поэтому правила iptables, которые нужно добавить, два:

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
Francesco
источник
3

В Linux у вас есть два других варианта:

Оба расширения ядра Linux позволяют предоставлять права доступа на очень мелком уровне. Это позволило бы вам разрешить этому процессу открыть порт 80, но он не наследовал бы ни одно из других корневых прав.

Из того, что я слышал, grsecurity намного проще в использовании, но SELinux более безопасен.

Аарон Дигулла
источник
2

Одним из решений является использование iptables для выполнения PAT на пакетах для порта 80. Это можно использовать, например, для маршрутизации пакетов на локальный порт 8080. Обязательно и настройте исходящие пакеты обратно на порт 80.

По моему опыту, детализированные функции разрешений Linux не скомпилированы в стандартные ядра из-за проблем безопасности.


источник
2

Если вы пытаетесь сделать это так, чтобы пользовательская команда могла использовать порт 80, то ваши единственные решения - это хитрости iptables или установка исполняемого файла setuid-to-root.

Способ, подобный Apache, делает это (он связывается с портом 80, но работает от имени другого пользователя, а не от root) - запускать от имени пользователя root, связываться с портом, а затем после владения портом менять владельца процесса на непривилегированного пользователя. настроен. Если приложение, которое вы пишете, может быть запущено пользователем root, вы можете изменить его владельца на непривилегированного пользователя после настройки портов. Но если это только для обычного пользователя, запускаемого из командной строки, то вам придется использовать одно из других решений.

rjray
источник
2

Когда у меня есть различные приложения для веб-обслуживания (скрипты Python, механизмы tomcat и т. Д.), Которые я не хочу запускать от имени пользователя root, я обычно настраиваю перед ними веб-сервер apache. Apache слушает порт 80, а tomcat слушает 8080.

В конфиге apache: s:

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

Для получения дополнительной информации см. Документацию мод-прокси: http://httpd.apache.org/docs/2.2/mod/mod_proxy.html.


источник
1
Недостатком этого решения является потеря входящего IP в журналах Tomcat.
Эммануэль Бур
2

Я думаю, что лучшим решением является sgid вашего приложения, и как только оно привязано к порту, оно должно отбросить привилегии, переключившись на другого пользователя.

Anxy Dicy
источник
1

Некоторые хост-системы не позволяют использовать модуль NAT, «iptables» не решает проблему в этом случае.

Как насчет xinetd?

В моем случае (Ubuntu 10.04)

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

Вставьте конфигурацию:

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

Затем:

# service xinetd restart

http://docs.codehaus.org/display/JETTY/port80 объясняет лучше.

Томас
источник
1
Это в основном эквивалентно размещению обратного прокси-сервера перед сервером, но это довольно неэффективно по сравнению с выделенными решениями, такими как HAproxy, Pound или Varnish, которые понимают протокол HTTP и могут добавлять полезные заголовки, такие как X-Forwarded-For.
Эммануэль Бур
-1

Кроме того, FreeBSD и Solaris (кто-нибудь помнит этот ?) Позволяют вам делать это (привязывать к низким портам) без повышения привилегий (то есть, используя программы для переключения в root). Поскольку вы указали Linux, я просто публикую это как уведомление для других, которые могут найти этот вопрос.

Даниэль С. Собрал
источник
-1

Necromancing.

Просто. С нормальным или старым ядром у вас нет.
Как отмечают другие, iptables может переадресовывать порт.
Как также отметили другие, CAP_NET_BIND_SERVICE также может выполнять эту работу.
Конечно, CAP_NET_BIND_SERVICE потерпит неудачу, если вы запустите свою программу из скрипта, если вы не установите ограничение на интерпретатор оболочки, что бессмысленно, вы можете просто запустить свой сервис как root ...
например, для Java вы должны применить его в JAVA JVM

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

Очевидно, это означает, что любая Java-программа может связывать системные порты.
Дито для моно / .NET.

Я также уверен, что xinetd не лучшая идея.
Но поскольку оба метода являются хакерами, почему бы просто не снять ограничение, сняв ограничение?
Никто не говорил, что вам нужно запустить нормальное ядро, поэтому вы можете просто запустить свое собственное.

Вы просто скачиваете исходный код для самого последнего ядра (или того же, что у вас есть в настоящее время). После этого вы идете к:

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

Там вы ищете эту строку

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

и изменить его на

#define PROT_SOCK 0

если вы не хотите иметь небезопасную ситуацию с ssh, измените ее следующим образом: #define PROT_SOCK 24

Как правило, я бы использовал самый низкий параметр, который вам нужен, например, 79 для http или 24 при использовании SMTP на порту 25.

Это уже все.
Скомпилируйте ядро ​​и установите его.
Перезагрузка.
Закончено - этот глупый предел ушел, и это также работает для сценариев.

Вот как вы собираете ядро:

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 ..

Короче говоря, используйте iptables, если вы хотите оставаться в безопасности, скомпилируйте ядро, если вы хотите быть уверенным, что это ограничение вас больше не беспокоит.

затруднительное положение
источник
Кто-нибудь, пожалуйста, объясните отрицательные голоса? Ядро-компиляция не работает? Или это просто потому, что после этого вы больше не можете обновлять ядро ​​из обычных репозиториев?
затруднительное
Я пробовал это решение ( sudo setcap cap_net_bind_service=+ep /path-to-java/java), но всегда получаю, java: error while loading shared libraries: libjli.so: cannot open shared object file: No such file or directoryесли в java установлены заглавные буквы. см. также первую часть unix.stackexchange.com/a/16670/55508
Даниэль Алдер,
1
Решено предыдущую ошибку, добавив <javahome>/lib/amd64/jli/к ld.so.confи работаетsudo ldconfig
Даниэль ольха