未分類

Jettyを80番ポートで、非rootユーザーで起動する

アプリケーションサーバ、サーブレットコンテナはDMZ(インターネットからアクセスできる場所)には置かず、フロントエンドにリバースプロキシとしてApacheやNginxなどのWebサーバーを立てて運用するのがベストプラクティスとされています。

mod_proxyやmod_jkを使ってhttpやajpで通信させても良いのですが、せっかくSPDYに対応しているのにもったいない!
またJettyはSPDY対応のリバースプロキシとしても機能します。DMZにJettyを置いてリバースプロキシとして動作させ、F/Wの後ろにもう1つJettyを置けばパフォーマンス的にもセキュリティ的にもイイ感じになるはず!

ただ問題なのはUnix系のプラットフォームでは一般ユーザーで80番ポートをリスンできないこと。
etc/jetty-http.xmlの
<Set name=”port”><Property name=”jetty.port” default=”8080″ /></Set>

<Set name=”port”><Property name=”jetty.port” default=”80″ /></Set>
と書き換えて起動しても以下のような例外が出て起動できません。

2012-12-04 08:47:59.323:WARN:oejuc.AbstractLifeCycle:main: FAILED ServerConnector@73c1f55{HTTP/1.1}{0.0.0.0:80}: java.net.SocketException: Permission denied
java.net.SocketException: Permission denied
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Net.java:344)
at sun.nio.ch.Net.bind(Net.java:336)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:199)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
at org.eclipse.jetty.server.ServerConnector.open(ServerConnector.java:227)
at org.eclipse.jetty.server.AbstractNetworkConnector.doStart(AbstractNetworkConnector.java:80)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:69)
at org.eclipse.jetty.server.Server.doStart(Server.java:287)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:69)
at org.eclipse.jetty.xml.XmlConfiguration$1.run(XmlConfiguration.java:1235)
at java.security.AccessController.doPrivileged(Native Method)
at org.eclipse.jetty.xml.XmlConfiguration.main(XmlConfiguration.java:1162)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.eclipse.jetty.start.Main.invokeMain(Main.java:452)
at org.eclipse.jetty.start.Main.start(Main.java:600)
at org.eclipse.jetty.start.Main.main(Main.java:95)

ApacheやWebLogic Serverなどはrootで起動して80番ポートをリスン開始した後にプロセスのユーザーを切り替える機能があります。ちなみにPure JavaでUnix/Linux固有のシステムコールができるはずはなく、Javaの標準APIでプロセスのユーザー切り替え
さてJettyは・・と調べたところありました。
How do I use port 80 as a non root user?

プロセスのユーザー切り替え用のネイティブライブラリがあり、etc/jetty-setuid.xmlで設定することになるようです。ただ最新のJetty9.0.0M3にはこのライブラリは同梱されていません。
GitHubからとってきて自分でビルドする必要があります。
しかしそのままではディレクトリが見つからない旨のビルドエラーが出ました
libsetuid_linuxをjetty-setuid-linuxに、libsetuid_osxをjetty-setuid-osxにリネームしたところビルド成功し、以下のファイルができあがりました。
jetty-setuid/jetty-setuid-osx/target/libsetuid_osx.so
jetty-setuid/jetty-setuid-osx/target/lib/jetty-setuid-java.jar

最新のソースコードでは問題なくビルドできる。ファイル名はちょっと異なり以下の通り。
jetty-setuid/libsetuid-osx/target/libsetuid-osx.so
jetty-setuid/libsetuid-osx/target/lib/jetty-setuid-java.jar

次に$JETTY_HOME/etc/jetty-setuid.xml を作成し以下のように記述

<Configure id="Server" class="org.eclipse.jetty.setuid.SetUIDServer">
<Set name="startServerAsPrivileged">false</Set>
<Set name="umask">2</Set>
<Set name="uid">501</Set>
<Set name="gid">20</Set>
</Configure>

uid、gidはidコマンドで取得できるものを指定。
例)

$ id yusuke
uid=501(yusuke) gid=20(staff) groups=20(staff),401(com.apple.access_screensharing),12(everyone),33(_appstore),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),100(_lpoperator),204(_developer)

関連記事:
u1aryzの備忘録とか: jetty8でport80起動