【APサーバ】Apache2とTomcat外部連携

TomcatをVMWearのCentOSに移してみようかと思い設定してみました。

  • Raspbian側の設定

    vi /etc/apache2/sites-available/default
    
    # 下記内容に変更
    <Location /examples/servlets/>
        ProxyPass ajp://localhost:8009/examples/servlets/
        allow from all
    </Location>
    ↓
    <Location /examples/servlets/>
        ProxyPass ajp://CentOSのIP:8009/examples/servlets/
        allow from all
    </Location>
    
    ufw disable
    
  • VMWearのCentOS側の設定

    /etc/rc.d/init.d/iptables stop
    

    「http://Raspbain側のIP/examples/servlets/」でアクセスして
    VMWearのCnetOS側にTomcatログが出力されているようであれば成功です。
    ・・・しかし私の環境では接続が上手く出来ませんでした。
    急いではいないので、また別の機会に試そうと思います。

  • バージョン確認の方法

    【CentOS】

    httpd -v
    $CATALINA_HOME/bin/version.sh
    
    Apache2:Server version: Apache/2.2.15 (Unix)
    Tomcat:Apache Tomcat/7.0.42
    Architecture:amd64
    JVM Version:1.7.0_45-b18
    Apache2とTomcatを連携済。
    

    【Raspbain】

    apache2 -v
    $CATALINA_HOME/bin/version.sh
    
    Apache2:Apache/2.2.22 (Debian)
    Tomcat:Apache Tomcat/7.0.55
    Architecture:arm
    JVM Version:1.7.0_40-b43
    Apache2とTomcatを連携済。
    

【WEBサーバ】アクセスログ確認

自宅サーバをもって約3週間。
アクセスログを確認してみると、何やらレスポンスを確認しているかような怪しいログが。
アクセスログをgpreしてみました。

zgrep "File does not exist" error*.log* >> /home/ユーザ名/result1.txt
zgrep "phpMyAdmin" access.log* >> /home/ユーザ名/result2.txt

gpre結果から自身のIPを除き、どこのパスにアクセスしているか、
確認すると下記のパスに連続してGETしていました。

/phpMyAdmin/scripts/setup.php
/myadmin/scripts/setup.php
/pma/scripts/setup.php

プロキシサーバ使われていると調べようもないですが、
IP元は台湾、タイ、中国、ドイツ、トルコ等様々。
アジアが多い感じ。

mySQLはCUIで触るので、そもそもphpMyAdminを導入していないから問題ないですが、勉強になりました。

【APサーバ】Tomcat起動ログ確認

Tomcatの起動ログ確認してみたところ、
予想はしていましたが、WARNINGやjarファイルに関するログが出てました。

【1つ目】

jar not loaded. See Servlet Spec

自動展開後の「$CATALINA_HOME/webapps/コンテキスト名/WEB-INF/lib」にあるjarファイルと
Tomcat固有で保持している「$CATALINA_HOME/lib」にあるjarファイルが重複していると
jarファイルをロードしていない旨のログが発生するようです。

というわけで、「el-api.jar」と「servlet-api.jar」を前者から削除しました。

【2つ目】

inside the host appBase has been specified, and will be ignored

コンテキスト名.xmlのdocBase属性値がTomcatのデフォルト設定値と等しい場合、
冗長な設定ということで、コンテキスト名.xmlを修正しました。

vi /tomcat/apache-tomcat-7.0.55/conf/Catalina/localhost/コンテキスト名.xml
# 下記内容を変更
<Context path="/コンテキスト名" reloadable="true" docBase="/tomcat/apache-tomcat-7.0.55/webapps/コンテキスト名" />
↓
<Context path="/コンテキスト名" />

reloadableも重そうな気がしたし、更新する時は大抵再起動するので、削除しました。
Tomcatを再起動すると、WARNINGやjarファイルに関するログは消えました。

Tomcatの再起動時にrestart指定で実行すると、まれにエラーが発生してる。
呼び出しが早すぎるのか、stopする前にstartが呼ばれてたりするのかはよくわからず。
stop指定してから3秒後くらいにstart指定で再起動するとエラーは発生せず。
今のところは気にせずいきます。

【APサーバ】warファイル配置

ローカル環境で作成しておいたwarファイルを
Raspberry PiのTomcatに配置するので、
まずはTomcatの設定を確認します。

vi /tomcat/apache-tomcat-7.0.55/conf/server.xml
# 下記内容が設定されていることを確認
<Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">

【unpackWARs】
webappsに配置したwarファイルを自動展開するかの設定。

【autoDeploy】
Tomcat動作中に自動的にアプリケーションをデプロイしてくれるようにするかの設定。

デフォルトで両方trueになっていたので、
自動展開しつつ、自動デプロイする設定になっているようです。
その場合、web.xmlがwarファイル内と自動展開したディレクトリ内にも
web.xmlが存在していることになるが、ディレクトリのweb.xmlを優先するようです。

というわけで、FTPで「/home/ユーザ名」にwarファイルを配置しておきます。

cp -pi /home/ユーザ名/ファイル名.war /tomcat/apache-tomcat-7.0.55/webapps

Tomcat起動状態で実施するとコピーした瞬間、自動展開されています。
root所有になっているので、Tomcat専用ユーザ所有に変えておきます。

chown -R Tomcat専用ユーザ名.Tomcat専用ユーザ名 自動展開されたディレクトリ名

Server.xmlに書くよりも個別でコンテキスト名.xmlを書く方が好きなので、
コンテキスト名.xmlを作成します。
ローカルに自動作成されているので、それを参考にしました。

cp -pi /home/ユーザ名/コンテキスト名.xml /tomcat/apache-tomcat-7.0.55/conf/Catalina/localhost/
chown -R Tomcat専用ユーザ名.Tomcat専用ユーザ名 コンテキスト名.xml
vi /tomcat/apache-tomcat-7.0.55/conf/Catalina/localhost/コンテキスト名.xml
# 下記内容を追加
<Context path="/コンテキスト名" reloadable="true" docBase="/tomcat/apache-tomcat-7.0.55/webapps/コンテキスト名" />
vi /etc/apache2/sites-available/default
# 下記内容を追加
<Location /コンテキスト名/>
        ProxyPass ajp://localhost:8009/コンテキスト名/
        allow from all
</Location>

下記URLにアクセスする。

http://z-area.net/コンテキスト名/

作成した画面が表示されれば成功。
初回のJSPはコンパイルが入るとはいえ、重すぎ。

アップロードしておいたファイルを削除しておきます。

rm -f /home/ユーザ名/ファイル名.war
rm -f /home/ユーザ名/コンテキスト名.xml

【APサーバ】Apache2とTomcat連携

Apache2とTomcatを連携させて
ポート番号を指定せずに画面表示出来るように設定します。

バーチャルホストの設定ファイルを変更します。

vi /etc/apache2/sites-available/default
<VirtualHost *:80>
    ~略~
    <Directory /var/www/>
        ~略~
    </Directory>
# 上記のすぐ下に下記内容を追加。(Directoryではなく、Locationです)
    <Location /examples/servlets/>
        ProxyPass ajp://localhost:8009/examples/servlets/
        allow from all
    </Location>

連携モジュールを有効化します。

a2enmod proxy_ajp
Considering dependency proxy for proxy_ajp:
Enabling module proxy.
Enabling module proxy_ajp.
To activate the new configuration, you need to run:
  service apache2 restart

Apache2を再起動する。

service apache2 restart

Tomcatの設定から8080ポートの設定をコメントアウトし、
8009ポートの設定がコメントアウトされていないことを確認する。

vi /tomcat/apache-tomcat-7.0.55/conf/server.xml
# 下記内容を変更する。(コメントアウト)
<Connector port="8080" protocol="HTTP/1.1" ~略~
↓
<!-- <Connector port="8080" protocol="HTTP/1.1" ~略~ -->

# 下記内容がコメントアウトされていないことを確認する。
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

下記URLにアクセスする。

http://z-area.net/examples/servlets/

Servletのサンプル画面が出てくれば成功。

http://z-area.net:8080/examples/servlets/

接続失敗すれば成功。

私の環境ではApahce2とTomcatともに再起動してもポート8080で表示できてしまったので、
サーバをrebootして、再度Apache2、Tomcatを起動したらポート8080で接続不可になっていました。

簡易ファイアウォールでポート8080を閉じる。

ufw delete allow 8080
Rule deleted
ufw status
ToActionFrom
20LIMITAnywhere
21LIMITAnywhere
22LIMITAnywhere
80ALLOWAnywhere
443ALLOWAnywhere

【APサーバ】JavaとTomcat導入

Raspberry Piでは性能的に重いと分かりつつも、
JavaとTomcatを導入してみます。

Raspberry PiではSwing、Appletを利用しないため、
Headful版ではなく、Headless版を選択しました。
SoftFP版とHardFP版の違いは調べてません。
TomcatはCoreの最新版を選択しました。

【Java】
Oracle Java SE Embedded version 7 Update 60
ARMv6/7 Linux - Headless - Client Compiler EABI, VFP, HardFP ABI, Little Endian1
ejre-7u60-fcs-b19-linux-arm-vfp-hflt-client_headless-07_may_2014.tar.gz

【Tomcat】
apache-tomcat-7.0.55.tar.gz

FTPで「/home/ユーザ名」にダウンロードしておいたファイルを配置しておきます。
Javaはファイル名長いのでjava.tar.gzに変えました。

  • Java導入

    mkdir /java
    cp -pi /home/ユーザ名/java.tar.gz /java
    cd /java
    tar xvzf java.tar.gz
    chown root.root -R ejre1.7.0_60
    rm -f /home/ユーザ名/java.tar.gz
    rm -f java.tar.gz
    
  • Tomcat導入
    Tomcatはroot以外のユーザで実行できるようにしておくと、
    OS全体が乗っ取られる可能性があるということで、Tomcat専用ユーザを作成します。

    adduser Tomcat専用ユーザ名
    

    変更後のパスワード入力。
    変更後のパスワード再入力。
    残りの項目は空でエンターを押下すれば問題なし。
    最後に”Y”を入力。

    mkdir /tomcat
    cp -pi /home/ユーザ名/apache-tomcat-7.0.55.tar.gz /tomcat
    cd /tomcat
    tar xvzf apache-tomcat-7.0.55.tar.gz
    chown Tomcat専用ユーザ名.Tomcat専用ユーザ名 -R apache-tomcat-7.0.55
    rm -f /home/ユーザ名/apache-tomcat-7.0.55.tar.gz
    rm -f apache-tomcat-7.0.55.tar.gz
    

    Tomcat用の起動スクリプトを作成します。

    vi /etc/init.d/tomcat.sh
    

    2重起動防止のチェック処理等は実装していません。

    #!/bin/sh
    # 環境変数を設定する。
    export JAVA_HOME=/java/ejre1.7.0_60
    export PATH=$PATH:$JAVA_HOME/bin
    export CLASSPATH=.:$JAVA_HOME/lib
    export CATALINA_HOME=/tomcat/apache-tomcat-7.0.55
    export CLASSPATH=$CLASSPATH:$CATALINA_HOME/lib
    
    # 第1引数の内容により条件分岐する。(start, stop, restart)
    case "$1" in
        'start')
            if [ -f /tomcat/apache-tomcat-7.0.55/bin/startup.sh ]; then
            echo "Starting the tomcat service"
            "/tomcat/apache-tomcat-7.0.55/bin/startup.sh"
            fi
        ;;
        'stop')
            echo "Stopping the tomcat service."
            "/tomcat/apache-tomcat-7.0.55/bin/shutdown.sh"
        ;;
        'restart')
            $0 stop
            $0 start
        ;;
        *)
            echo "Usage: $0 {start|stop|restart}"
        ;;
    esac
    
    exit 0
    

    実行権限を付与し、シェルを起動する。

    chmod +x /etc/init.d/tomcat.sh
    /etc/init.d/tomcat.sh start
    

    下記URLにアクセスする。

    http://z-area.net:8080/examples/servlets/

    Servletのサンプル画面が出てくれば成功。
    現在はポート8080は閉じているため、外部からは開けません。

    次に自動起動できるように設定します。

    insserv /etc/init.d/tomcat.sh
    insserv: warning: script 'tomcat.sh' missing LSB tags and overrides
    

    タグがないと警告でていますが、気にしない方向で。
    参考までに自動起動を停止する場合、は下記の通り。

    insserv -r /etc/init.d/tomcat.sh
    

    以前までは「update-rc.d」で自動起動していたようですが、
    Debian6以降では「insserv」が推奨のようです。
    CentOSは「chkconfig」だったりとこの辺は勉強しないと分からない点が多いです。

【Eclipse】Eclipseのwarファイル出力

プロジェクトを右クリックし、エクスポートから「Web」-「WARファイル」を選択。
Webプロジェクト名:任意名
宛先:任意の出力ファイル名

画面に従いそのままwarファイルを出力しようとすると
「モジュール名が無効です。」とエラーが出て出力できない・・・。
原因はTomcatプロジェクトになっているからで、
動的Webプロジェクトに変更すれば良いので、手順をメモしておきます。

プロジェクトを右クリックし、プロパティから「プロジェクト・ファセット」を選択。
変な英字リンクをクリックするとチェックボックスがたくさんある画面が開くので、
「Xdoclet付き動的Webプロジェクト」を選択してから下記の通り修正。

Java:1.7 バージョンを変更しました。
JavaScript:1.0 チェックボックスを付けました。
WebDoclet:チェックボックスを外しました。
動的Webモジュール:2.4

上記設定を行い、「適用」ボタン押下。
設定が完了するとプロジェクトに地球儀がついて、warファイル出力が出来るように。

ついでにjarファイルの配置メモ。

Tomcatプロジェクト:「ファイル」-「新規」-「その他」-「Java」-「Tomcatプロジェクト」

【配置jarファイル】
(1) JREシステムライブラリー7.0
(2) eclipseJP-tomcat-7.0-lib
  ⇒jsp-api.jarファイルやel-api.jarファイル
(3) eclipseJP-workspace-プロジェクト名-WEB-INF-lib
  ⇒poiやmysqlのjarファイル

【Javaのビルド・パス】
(1)、(2)、(3)
動的Webプロジェクト:「ファイル」-「新規」-「動的Webプロジェクト」

【配置jarファイル】
(1) JREシステムライブラリー7.0
(2) WebAppライブラリー
  ⇒(4)と(5)のjarファイル、warファイルをエクスポート時にも利用
(3) EARライブラリー
  ⇒配置なし
(4) eclipseJP-tomcat-7.0-lib
  ⇒jsp-api.jarファイルやel-api.jarファイル
(5) eclipseJP-workspace-プロジェクト名-WEB-INF-lib
  ⇒poiやmysqlのjarファイル

【Javaのビルド・パス】
(1)、(2)、(3)

【Java】ApachePOI

自社出勤簿はExcel管理されており、毎月月末に入力するのが面倒なので
Webから退社時刻だけ入力したら自社出勤簿に保存されるようにPOIを使ってみることに。
利用したPOIは「poi-bin-3.10.1-20140818」です。

自社出勤簿はいまだにExcel2003なのでHSSFXXXのオブジェクトを利用します。
両方を扱えるインターフェースもあるようです。

HSSFXXX:Excel2003のファイルフォーマット(.xls)を扱うオブジェクト
XSSFXXX:Excel2007のファイルフォーマット(.xlsx)を扱うオブジェクト
// Excelファイル取得
POIFSFileSystem filein = new POIFSFileSystem(new FileInputStream(String 入力ファイルのフルパス));

// ワークブック取得
HSSFWorkbook wb = new HSSFWorkbook(filein);
// シート取得
HSSFSheet sheet = wb.getSheet(String シート名);
// 行数取得
HSSFRow row = sheet.getRow(int 行数);

// 列取得(出社時刻用)
HSSFCell cellFirst = row.getCell(int 列数);
// 出社時刻設定
cellFirst.setCellValue(double 出社時刻);

// 列取得(退社時刻用)
HSSFCell cellEnd = row.getCell(int 列数);
// 退社時刻設定
cellEnd.setCellValue(double 退社時刻);

// ワークブック強制再計算
wb.setForceFormulaRecalculation(true);
// Excelファイル保存
wb.write(new FileOutputStream(String 出力ファイルのフルパス));

出社時刻、退社時刻をdouble型にしている理由ですが、
自社出勤簿の出社時刻、退社時刻はExcelのセルを確認すると
ユーザ定義で「h:mm」の時刻形式で、当日勤務時間や残業時間は自動計算されるようになっています。

Excelを使って入力した場合、下記の通りの表示となり、
画面表示:9:00 18:00
セル内値:9:00:00 18:00:00
出勤簿計算結果:正常

それと同じ画面表示、セル内値にしたいので、
Excel側にはシリアル値(1900年1月1日を1として算出した数値)を渡す必要があり、
double型をsetCellValueに渡しています。

// 時
double hh = Double.parseDouble("0900".substring(0,2))*(1.0/24.0);
// 分
double mm = Double.parseDouble("0900".substring(2,4))*(1.0/24.0/60.0);

setCellValueは受け取れる型が下記の通り複数あるので、StringとDateで試してみました。
java.lang.String
java.util.Date
java.util.Calendar
double
boolan
RichTextString

【お試し:String】

cellFirst.setCellValue("09:00");
cellEnd.setCellValue("18:00");

画面表示:09:00 18:00
セル内値:09:00 18:00
出勤簿計算結果:正常
⇒画面表示とセル内値がちょっと違う。

【お試し:Date】

SimpleDateFormat hhmmFormat = new SimpleDateFormat("h:mm");
cellFirst.setCellValue(hhmmFormat.parse("09:00"));
cellEnd.setCellValue(hhmmFormat.parse("18:00"));

画面表示:613655:00 613674:00
セル内値:1970/1/1 9:00:00 1970/1/1 18:00:00
出勤簿計算結果:正常
⇒何か色々違う

【WEBサーバ】Apache2設定ファイル

RedHatとDebianでApache2の仕様がだいぶ違うので、メモ程度に記載。
RedHatはVMのCentOS、DebianはRaspberry PiのRaspbainを元にしています。

RedHat:設定は「httpd.conf」で行う。
Debian:設定は外部設定ファイルで行い、かつ、利用する機能分をシンボリックリンクで別管理する。
下記に詳細。

  • RedHat(CentOS)

    【基本設定ファイル】
    /etc/httpd/conf/httpd.conf
    ServerTokensの設定、Timeoutの設定、
    利用モジュールの配置場所、利用モジュールの設定ファイル配置場所
    バーチャルホスト設定等を設定する。

    例) /etc/httpd/conf/httpd.conf
    # ServerTokensの設定
    ServerTokens Prod
    
    # Timeoutの設定
    Timeout 60
    
    # 利用モジュールの配置場所
    LoadModule rewrite_module modules/mod_rewrite.so
    
    # 利用モジュールの設定ファイル配置場所
    include conf.d/ssl.conf
    
    # バーチャルホスト設定
    <VirtualHost *:80>
    

    【利用モジュールの設定ファイル】
    /etc/httpd/conf.d/モジュール.conf
    利用モジュールの各種動作を設定する。

    例) /etc/httpd/conf.d/ssl.conf
    # 証明書のパス
    SSLCertificateFile 証明書のパス
    
  • Debian(Raspbain)

    【基本設定ファイル】
    /etc/apache2/apache2.conf
    Timeoutの設定、追加設定ファイル配置場所、
    利用モジュールの配置場所、利用モジュールの設定ファイル配置場所、
    バーチャルホスト設定ファイル配置場所等を設定する。
    ServerTokensの設定は追加設定ファイルで行う。

    例) /etc/apache2/apache2.conf
    # Timeoutの設定
    Timeout 60
    
    # 追加設定ファイル配置場所
    Include conf.d/
    
    # 利用モジュールの配置場所
    Include mods-enabled/*.load
    
    # 利用モジュールの設定ファイル配置場所
    Include mods-enabled/*.conf
    
    # バーチャルホスト設定ファイル配置場所
    Include sites-enabled/
    

    【追加設定ファイル】
    /etc/apache2/conf.d/追加設定名
    ServerTokensの設定、文字コードの設定を行う。

    例) /etc/apache2/conf.d/security
    # ServerTokensの設定
    ServerTokens ProductOnly
    

    【利用モジュールの設定ファイル】
    /etc/apache2/mods-available/モジュール.conf
    利用モジュールの各種動作を設定する。

    例) /etc/apache2/mods-available/dav_svn.conf
    # SVNのパス
    SVNParentPath /var/www/svn
    

    【バーチャルホスト設定ファイル】
    /etc/apache2/sites-available/バーチャルホスト
    バーチャルホストを設定する。

    例) /etc/apache2/sites-available/default
    <VirtualHost *:80>
    
  • 「/etc/apache2」のディレクトリ構成
    apache2.conf
    ├ conf.d/security
    ├ mods-enabled/モジュール.load ⇒ mods-available/モジュール.load
    ├ mods-enabled/モジュール.conf ⇒ mods-available/モジュール.conf
    └ sites-enabled/バーチャルホスト ⇒ sites-available/バーチャルホスト

    基本設定ファイルに記載している「mods-enabled」、「sites-enabled」には
    実ファイルではなく、シンボリックリンクが配置されており、
    実ファイルは「mods-available」、「sites-available」に配置されている。

    モジュールの有効化と無効化

    a2enmod モジュール
    a2dismod モジュール
    

    バーチャルホストの有効化と無効化

    a2ensite バーチャルホスト
    a2dissite バーチャルホスト
    

【Eclipse】EclipseでSubversion

  • EclipseからSubversion参照
    ローカル環境のEclipseから「ウィンドウ」-「パースペクティブを開く」-「その他」で「SVNリポジトリ―・エクスプローラー」を選択。
    「新規リポジトリ―・ロケーション」ボタンを押下。

    一般タブ
    URL:http://z-area.net/svn/z-test/

    認証タブ
    ユーザ:ユーザ名
    パスワード:パスワード

    証明書の信頼性に云々と警告が出ますがオレオレ証明書なので常に信頼。
    これでSubversionを参照し、コミット済のプロジェクトをチェックアウトしたりできます。

  • EclipseからSubversionコミット
    ローカル環境のEclipseからJavaEEのプロジェクト・エクスプローラーのプロジェクトで右クリック。
    「チーム」-「プロジェクトの共用」を選択。
    SVNを選択。
    既存のリポジトリ―・ロケーションを使用を選択。
    シンプル・モードを選択。
    完了ボタン押下。

    これで新規プロジェクトをSubversionへコミットできます。