LoginSignup
5
4

More than 5 years have passed since last update.

Amazon Linux と Jetty で HTTP/2 な GitBucket サーバーを建てる。

Last updated at Posted at 2016-03-14

GitBucket の運用サーバーを HTTPS 対応で建てたいという動機からスタート。Tomcat と Apache のような組み合わせではなく、もっとライトに建てたかったので、GitBucket のビルトインサーバーでも採用されている Jetty を試した。

HTTP サーバー兼 Java サーブレットを一つで提供してくれて、先進機能も豊富、設定項目の自由度、ポータビリティと言った利点に惹かれた。

注意: だいたい設定できたけどデーモン化して起動しようとすると java.lang.NoClassDefFoundError というエラーで失敗する問題が未解決です。助けて。

tl;dr

サーバーの構成は次のように定義した:

環境変数 説明
JETTY_HOME /opt/jetty Jetty 実行ディレクトリのパス。
JETTY_BASE /var/jetty Jetty データディレクトリのパス。
JETTY_USER jetty Jetty を実行する Linux ユーザー名。
GITBUCKET_HOME /var/gitbucket GitBucket データディレクトリのパス。
N/A /opt/gitbucket GitBucket 実行ディレクトリのパス。
  • 上記ディレクトリは jetty ユーザーの所有とした。
  • JETTY_HOME は実ディレクトリ /opt/jetty-distribution-9.3.7.v20160115 のシンボリックリンクとした。
  • この他 GitBucket の実行ファイルパスは /opt/gitbucket/gitbucket.war としている。

Amazon Linux

セットアップ

Security Group で 80 と 443 ポートを開放する。

iptables で Jetty 標準の HTTP ポート 8080 と HTTPS ポート 8443 をポートフォワーディングして、80443 に設定する:

sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443
sudo service iptables save
  • 80443 に Jetty のポートを変更するには実行ユーザーを root にする必要がある。それを避けるためにポートフォワーディングを使用する。1

Jetty の実行ユーザー jetty を作成する:

sudo adduser \
  --comment 'User running Jetty server' \
  --home /home/jetty \
  --create-home \
  --system \
  --shell /bin/bash \
  --user-group \
  jetty

Java

インストール

Amazon Linux は OpenJDK を yum コマンドからインストールできる。しかし、HTTPS 暗号化通信のアルゴリズムの一部が実装されていないとかで、Oracle 純正 JDK をダウンロードして使用する。

現状最新の jdk-8u74-linux-x64.rpm をダウンロードしてインストールする:

curl -L \
  http://download.oracle.com/otn-pub/java/jdk/8u74-b02/jdk-8u74-linux-x64.rpm \
  | sudo rpm -Uvh -

alternatives コマンドでデフォルトの Java 環境をインストールしたものに変更する:

sudo alternatives --config java
There is 3 program that provides 'java'.

  Selection    Command
-----------------------------------------------
   1           /usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin/java
   2           /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java
*+ 3           /usr/java/jdk1.8.0_74/jre/bin/java

Enter to keep the current selection[+], or type selection number: 3

GitBucket

インストール

GitBucket は手動インストールのみ。

最新の gitbucket.war をダウンロードして設置する:

# /opt/gitbucket 以下にダウンロード
sudo mkdir -p /opt/gitbucket
cd /opt/gitbucket
sudo curl -LO https://github.com/gitbucket/gitbucket/releases/download/3.12/gitbucket.war
# 所有者は jetty ユーザーに
sudo chown jetty:jetty -R /opt/gitbucket

GITBUCKET_HOME として /var/gitbucket ディレクトリを作成する:

# GITBUCKET_HOME ディレクトリを作成
sudo mkdir -p /var/gitbucket
# 所有者は jetty ユーザーに
sudo chown jetty:jetty -R /var/gitbucket

Jetty

インストール

Amazon Linux は yum コマンドで Jetty のインストールに対応していないので、手動で導入する。

現状最新の jetty-distribution-9.3.7.v20160115.tar.gz をダウンロードしてインストールする:

# ダウンロードした書庫を /opt 以下に展開
curl -L \
  http://download.eclipse.org/jetty/9.3.7.v20160115/dist/jetty-distribution-9.3.7.v20160115.tar.gz \
  | sudo tar zxvf - -C /opt
# /opt/jetty としてシンボリック化
ln -s /opt/jetty-distribution-9.3.7.v20160115 /opt/jetty

/opt/jetty-distribution-9.3.7.v20160115 (/opt/jetty) 以下は jetty ユーザーの所有に変更する:

sudo chown jetty:jetty -R /opt/jetty-distribution-9.3.7.v20160115

前述の Java 環境 jdk-8u74 に対応する Jetty ライブラリ alpn-1.8.0_74.mod は、上記パッケージには含まれていない。なので別途ダウンロードして、然るべきパスに配置する:

# jetty ユーザーで作業
sudo su - jetty
# /opt/jetty/modules/alpn-impl 以下に alpn-1.8.0_74.mod をダウンロード
cd /opt/jetty/modules/alpn-impl
curl -LO https://raw.githubusercontent.com/eclipse/jetty.project/master/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_74.mod

セットアップ

JETTY_BASE となるディレクトリを作成し、必要なモジュールをインストールする:

# jetty ユーザーで作業
sudo su - jetty
# JETTY_BASE ディレクトリを作成
mkdir -p /var/jetty
# JETTY_BASE ディレクトリにモジュールをインストール
cd /var/jetty
java -jar /opt/jetty/start.jar \
  --add-to-start=deploy,http,https,http2,logging

作成された start.ini に次の設定を追加し、HTTP 通信でアクセスがあった時のリダイレクト先 HTTPS 通信のポート番号を指定する2:

# jetty ユーザーで作業
sudo su - jetty
# start.ini に設定項目を追加
vi /var/jetty/start.ini
/var/jetty/start.ini
229,235d228
< # HTTP 通信でアクセスがあった時のリダイレクト先 HTTPS 通信のポート番号
< # http://www.eclipse.org/jetty/documentation/current/configuring-ssl.html#d0e4938
< jetty.httpConfig.securePort=443
<

GitBucket 用のセットアップ

JETTY_BASEwebapps ディレクトリ下に gitbucket.xml を作成し;

  • サーバールートで GitBucket を動作させる設定と
  • HTTPS 通信にリダイレクトする設定3

を定義する:

# jetty ユーザーで作業
sudo su - jetty
# gitbucket.xml を作成
touch /var/jetty/webapps/gitbucket.xml
/var/jetty/webapps/gitbucket.xml
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.webapp.WebAppContext">
  <!-- ルートパスで GitBucket を動作させる -->
  <Set name="contextPath">/</Set>
  <Set name="war">/opt/gitbucket/gitbucket.war</Set>

  <!-- HTTPS 通信を宣言する -->
  <!-- https://wiki.eclipse.org/Jetty/Howto/Configure_SSL#Redirecting_http_requests_to_https -->
  <Set name="securityHandler">
    <New class="org.eclipse.jetty.security.ConstraintSecurityHandler">
      <Call name="addConstraintMapping">
        <Arg>
          <New class="org.eclipse.jetty.security.ConstraintMapping">
            <Set name="pathSpec">/*</Set>
            <Set name="constraint">
              <New class="org.eclipse.jetty.util.security.Constraint">
                <!-- 2 means CONFIDENTIAL. 1 means INTEGRITY -->
                <Set name="dataConstraint">2</Set>
              </New>
            </Set>
          </New>
        </Arg>
      </Call>
    </New>
  </Set>
</Configure>
  • gitbucket.warwebapps 内に設置しなくても gitbucket.xml に war ファイルのパスが設定されてれば問題ないみたいだ。

デーモン化

デーモン化するため /etc/default/jetty を作成し、必要な環境変数を定義する:

sudo touch /etc/default/jetty
/etc/default/jetty
JETTY_HOME=/opt/jetty
JETTY_BASE=/var/jetty
JETTY_USER=jetty
GITBUCKET_HOME=/var/gitbucket

デーモン化用スクリプトは Jetty のパッケージに含まれているので、これをコピーして配置する:

sudo cp /opt/jetty/bin/jetty.sh /etc/init.d/jetty

サーバー起動時にも自動起動するよう設定する:

sudo chkconfig --add /etc/init.d/jetty
sudo chkconfig jetty on

自動起動が設定されているのを確認する:

sudo chkconfig --list jetty
jetty           0:off   1:off   2:on    3:on    4:on    5:on    6:off

デーモンを起動する:

sudo service jetty start

ここまでやったが、デーモン起動するとエラーで終了してしまう...

Starting Jetty: StartLog to /var/jetty/logs/start.log
2016-03-15 00:00:00.986:INFO::main: Logging initialized @142ms
2016-03-15 00:00:01.086:INFO::main: Redirecting stderr/stdout to /home/jetty/logs/2016_03_15.stderrout.log
FAILED Tue Mar 15 00:00:04 UTC 2016
/home/jetty/logs/2016_03_15.stderrout.log
Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/jetty/alpn/ALPN$ServerProvider
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        at java.lang.Class.getDeclaredConstructors0(Native Method)
        at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
        at java.lang.Class.getConstructors(Class.java:1651)
        at org.eclipse.jetty.util.TypeUtil.construct(TypeUtil.java:567)
        at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.newObj(XmlConfiguration.java:787)
        at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.itemValue(XmlConfiguration.java:1233)
        at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.value(XmlConfiguration.java:1138)
        at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.access$500(XmlConfiguration.java:274)
        at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration$AttrOrElementNode.getList(XmlConfiguration.java:1366)
        at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration$AttrOrElementNode.getList(XmlConfiguration.java:1341)
        at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.call(XmlConfiguration.java:704)
        at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.configure(XmlConfiguration.java:417)
        at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.configure(XmlConfiguration.java:358)
        at org.eclipse.jetty.xml.XmlConfiguration.configure(XmlConfiguration.java:259)
        at org.eclipse.jetty.xml.XmlConfiguration$1.run(XmlConfiguration.java:1498)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.eclipse.jetty.xml.XmlConfiguration.main(XmlConfiguration.java:1435)
Caused by: java.lang.ClassNotFoundException: org.eclipse.jetty.alpn.ALPN$ServerProvider
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 29 more

とり急ぎ nohup でバックグラウンド実行してお茶を濁している:

sudo su - jetty
cd /var/jetty
GITBUCKET_HOME=/var/gitbucket nohup java -jar /opt/jetty/start.jar 2>&1 | logger &

参考

TODO

  • デーモンで起動するとエラーで失敗する問題の解決
  • HTTP 通信を HTTPS 通信に自動リダイレクトさせる設定
  • SSL 証明書の発行と設定
  • cloud-init 化
5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4