Aipo7をCentOS9で動かす

# はじめに

SakuraVPS(CentOS6)にて構築している『AIPO7』があるのですが、CentOS6のサポートが終了していまして、yum コマンドも使えなくなっている状況です。（裏技はあるみたいですが信用しきれない）。yumが使えないのでサーバーがおかしくなったときに復旧できなくなる恐れがありますのでなんとかしておきたいところです。

そこでサポート継続しているCentOS9へ『AIPO7』を移行しておきたいという奇抜なことをお考えの方々向けに、次のことを検証してみました。本当は自分のための記録なのですが、一応カッコつけてみました（笑）。

- Aipo7 を CentOS9で動かせるか？
- AIPO7(Tomcat)をリバースプロキシで動かすときの問題点

なかなか面白い体験だったなと思いましたので、公開（記録）してみました。

## 想定する読者

- AIPO7を使い続けたい！といういう方々（組織）
- 未来の自分自身

Aipo7を使い続けたいと思っている方々へ向けて、お役にたつヒントを届けることができたら嬉しいなと思います。

## 記事の概要

- AIPO7をインストールした結果(CentOS9)
- AIPO8をインストールした結果(CentOS9)
- AIPO8をAIPO7にすり替えた結果
- Apache2のリバースプロキシでAIPO7を動かした結果
- NginxのリバースプロキシでAIPO7を動かした結果


## 本記事の前提事項

### SakuraVPS(1G)
```
・OS: CentOS Stream 9
・Kernel: Linux 5.14.0-474.el9.x86_64
・管理ユーザ: centos
・Sakuraのパケットフィルター： TCP 80, 443 22 のみを通す 
・Firewall: 有効にしていない
```

### 使用するAIPOのバージョン

```
・ AIPO7 (7.0.2)
・ AIPO8 (8.1.1)
```

### メモリスワップ領域拡張

契約したSakuraVPSサーバーはメモリ1G であり、メモリサイズに不安があるのでメモリスワップできるようにしています。

```
$ sudo dd if=/dev/zero of=/swapfile bs=1M count=1024
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile
$ echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
```

# 事前作業

## 必要パッケージをインストール

```
$ sudo dnf update -y
$ sudo dnf install net-tools wget tar zip unzip -y
$ sudo dnf libnsl -y
$ sudo dnf gcc readline-devel zlib-devel nmap lsof -y
```
libnsl はCentOS9には標準で入っていないようで、AIPO7を実行するときに必要ですので入れておきます。
gcc,readline-devel,zlib-devel,nmap,lsof　は AIPO7,AIPO8のインストールにて必要になりますので入れておきます。※ zip unzip は、本記事内の操作では使用していませんでしたね。すいません。

```
$ dnf list --installed | grep -e libnsl -e gcc -e zlib -e nmap -e lsof
gcc.x86_64                            11.5.0-2.el9                    @appstream
libgcc.x86_64                         11.5.0-2.el9                    @baseos
libnsl.x86_64                         2.34-133.el9                    @baseos
lsof.x86_64                           4.94.0-3.el9                    @baseos
nmap.x86_64                           3:7.92-3.el9                    @appstream
nmap-ncat.x86_64                      3:7.92-3.el9                    @appstream
zlib.x86_64                           1.2.11-41.el9                   @anaconda
zlib-devel.x86_64                     1.2.11-41.el9                   @appstream
```

# AIPO7のインストール(CentOS9)

## AIPO7の入手

インストーラーセットを紛失しているときは、『mirrors.dotsrc.org』より入手しましょう。

作業ディレクトリは、ユーザー「centos」のホームディレクトリとしています。

```
$ pwd
/home/centos
$ mkdir aipo7
$ cd aipo7
$ wget https://mirrors.dotsrc.org/osdn/aipo/60038/aipo7020aja_linux64.tar.gz
```

## インストーラーの展開

```
$ pwd
/home/centos/aipo7
$ tar xvzf aipo7020aja_linux64.tar.gz
```

## インストール手順
### 展開した結果を確認します。
```
$ pwd
/home/centos/aipo7/aipo7020aja_linux
$ ls 
aipo7020.tar.gz  readme.txt
```
### AIPOインストール先は /usr/local/aipo
/usr/local 直下に aipoディレクトリが作成されます。
```
$ cd /usr/local
$ ls
bin  etc  games  include  lib  lib64  libexec  sbin  share  src
$ sudo cp ~/aipo7/aipo7020aja_linux/aipo7020.tar.gz ./
$ sudo tar xvzf aipo7020.tar.gz
$ sudo rm aipo7020.tar.gz
$ ls 
aipo bin  etc  games  include  lib  lib64  libexec  sbin  share  src
```

### インストールスクリプトの実行権限
bin/installer.sh に実行権限がついていないのでつけてあげます
```
$ cd /usr/local/aipo
$ ls
backup  bin  license  logs  src
$ ls -l bin/installer.sh
-rw-r--r-- 1 root root  506 Nov  7  2012 installer.sh
$ sudo chmod 755 bin/installer.sh
-rwxr-xr-x 1 root root  506 Nov  7  2012 installer.sh
```

### ネットワークインタフェース記述の修正

１番目のネットワークインタフェースを確認しておきます（今回はens3)
inetとbroadcast の xxx.xxx.xxx.xxx のところは実際には存在するIPですが、ここではマスクしてます（etherのところもマスクしてます）。
```
$ ifconfig
ens3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet xxx.xxx.xxx.xxx  netmask 255.255.254.0  broadcast xxx.xxx.xxx.xxx
        ether xx:xx:xx:xx:xx:xx  txqueuelen 1000  (Ethernet)
        RX packets 2099080  bytes 690661057 (658.6 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 336622  bytes 82290808 (78.4 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
以下省略
```
bin/install.conf の記述を修正します。(今回は、eth0 ⇒ ens3 )
```
$ sudo vi bin/install.conf
=== 修正前 ===
netitf=eth0
dest_str=linux
check_pass=false
enc_str=utf8
def_addr=127.0.0.1

=== 修正後 ===
netitf=ens3
dest_str=linux
check_pass=false
enc_str=utf8
def_addr=127.0.0.1
```

### AIPO7のインストーラー実行

```
$ pwd
/usr/local/aipo
$ sudo bin/installer.sh
```
tomcat/postgresのコンパイル(gcc/make)が行われます。
実行前にユーザ(aipo_postgres)が存在しているのであれば、事前に削除しておいてください。
```
$ sudo userdel -r aipo_postgres
```

### インストールした結果

手順どおりにインストーラーを実行すると 次の結果になります。
以下は実行時のログの抜粋です。
```
(途中省略)
createdb: could not connect to database postgres: could not connect to server: No such file or directory
        Is the server running locally and accepting
        connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
psql: could not connect to server: No such file or directory
        Is the server running locally and accepting
        connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
psql: could not connect to server: No such file or directory
        Is the server running locally and accepting
        connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
psql: could not connect to server: No such file or directory
        Is the server running locally and accepting
        connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
cp: cannot stat '/usr/local/aipo/postgres/data/pg_hba.conf': No such file or directory
psql: could not connect to server: No such file or directory
        Is the server running locally and accepting
        connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
(以降省略)
```

PostgresDBのDataが入る/usr/local/aipo/postgres/data の中が空のままで、postgresをスタートできません。
インストーラースクリプトに不良があるようですが、原因を特定する余裕がないのであきらめることにします。
gcc によるコンパイルに不良がでているような気もかなりしているのですけどソース入手をしてまで解析する暇はありません。（gcc が新しすぎてコンパイルできないのかもと直感）

## 結論（2024/11/1時点)

CentOS9 へ AIPO7をダイレクトにインストールできない。
postgresコンパイルの過程で問題が起きている気がする。
古いgccセットを用意すればなんとかなるかもしれないが、そこまで制限をつけたくないし。



# AIPO8のインストール(CentOS9)

## AIPO7を消す

```
$ sudo userdel -r aipo_postgres
$ cd /usr/local
$ sudo rm -rf aipo
```

## AIPO8の入手

作業ディレクトリは、ユーザー「centos」のホームディレクトリとしています。

```
$ pwd
/home/centos
$ mkdir aipo8
$ cd aipo8
$ wget https://mirrors.dotsrc.org/osdn/aipo/64847/aipo-8.1.1-linux-x64.tar.gz
```

## インストーラーの展開

```
$ pwd
/home/centos/aipo8
$ tar xvzf aipo-8.1.1-linux-x64.tar.gz
$ ls
aipo-8.1.1-linux-x64 aipo-8.1.1-linux-x64.tar.gz
```

## インストール手順
### 展開した結果を確認します。
```
$ pwd
/home/centos/aipo8/aipo-8.1.1-linux-x64
$ ls 
bin  dist  installer.sh  readme.txt
```
### スクリプト修正(bin/varidate.sh)

lsof の存在チェックのところを修正します( /usr/sbin ⇒ /usr/bin )
```
$ vi bin/validate.sh
====修正前====
if [ -x /usr/sbin/lsof ]; then
        echo "lsof OK."
else
        tmp_packages=$tmp_packages"lsof "
fi

====修正後====
if [ -x /usr/bin/lsof ]; then
        echo "lsof OK."
else
        tmp_packages=$tmp_packages"lsof "
fi
```

### AIPO8のインストーラー実行

```
$ cd `/aipo8/bin
$ pwd
/home/centos/aipo8/bin
$ sudo ./installer.sh
```
tomcat/postgresのコンパイル(gcc/make)が行われます。
実行前にユーザ(aipo_postgres)が存在しているのであれば、事前に削除しておいてください。
```
$ sudo userdel -r aipo_postgres
```

### インストールした結果
こんなのが表示されたらインストール成功です。
```
Aipo のインストールが完了しました。
バージョン　　　　　: 8.1.1.0
インストール先　　　: /usr/local/aipo
PostgreSQLユーザー　: aipo_postgres
PostgreSQLパスワード: d28V8EdGWBZB

アクセス先:
http://xxx.xxx.xxx.xxx
ID/PASSWORD:
admin/admin

起動方法:
/usr/local/aipo/bin/startup.sh
停止方法:
/usr/local/aipo/bin/shutdown.sh

```
アクセス先の xxx.xxx.xxx.xxx は実際には存在するIPですが、ここでは x でマスクしています。
PostgreSQLパスワードはランダムに変わるので気にしないでください。PostgreSQLユーザーがaipo_postgres0になったときは、aipo_posgres ユーザの削除忘れですので、２つのaipo_postgresユーザを消し、/usr/local/aipo を削除してから、やり直してください。

### AIPO8 起動

```
$ cd /usr/local/aipo
$ sudo bin/startup.sh
```
この段階で、ブラウザ(AIPO)表示が可能です。
http://(HostIP)/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/529f7262-0154-8f5a-fa84-898275b3d212.png)

### AIPO8 停止

```
$ sudo bin/shutdown.sh
```

AIPO用の postgresプロセス、tomcatプロセスが停止します。

# AIPO8をAIPO7で入れ替える

## Tomcat(webapps)
```
$ cd /usr/local/aipo/tomcat/webapps
$ sudo rm -rf container
$ sudo cp -r ~/aipo7/aipo7020aja_linux/aipo/src/webapps/aipo ./
```

## Tomcat設定修正(JRE_HOME追記)
JRE_HOMEの設定を追記します。(Tomcatの起動スクリプト、停止スクリプト)
```
$ cd /usr/local/aipo
$ sudo vi tomcat/bin/startup.sh
==== JRE_HOME設定を追加
#!/bin/sh
# 最初の方に追加するとよい
export JRE_HOME=/usr/local/aipo/jre
# 以下略
====

$ sudo vi tomcat/bin/shutdown.sh
==== JRE_HOME設定を追加
#!/bin/sh
# 最初の方に追加するとよい
export JRE_HOME=/usr/local/aipo/jre
# 以下略
====
```

## dbcp-org001.properties

```:dbcp-org001.properties
$ sudo vi tomcat/webapps/aipo/WEB-INF/datasource/dbcp-org001.properties

==== 修正前 =====
cayenne.dbcp.driverClassName=org.postgresql.Driver
cayenne.dbcp.url=jdbc:postgresql://localhost:5432/org001
cayenne.dbcp.username=postgres
cayenne.dbcp.password=aipo
cayenne.dbcp.maxActive=100
cayenne.dbcp.minIdle=3
cayenne.dbcp.maxIdle=20
cayenne.dbcp.maxWait=10000

==== 修正後 =====
cayenne.dbcp.driverClassName=org.postgresql.Driver
cayenne.dbcp.url=jdbc:postgresql://localhost:5432/org001
cayenne.dbcp.username=aipo_postgres
cayenne.dbcp.password=d28V8EdGWBZB
cayenne.dbcp.maxActive=100
cayenne.dbcp.minIdle=3
cayenne.dbcp.maxIdle=20
cayenne.dbcp.maxWait=10000
```

cayenne.dbcp.username は aipo_postgres とする。
cayenne.dbcp.passwordは、aipo8インストール時のものを使うこと。

## DBの中身をAIPO7に入れ替え

### 移行元のAIPO7のDBダンプ
移行元AIPO7のサーバーにログインしてダンプしましょう。
```:移行元AIPO7のサーバー
$ cd /usr/local/aipo
$ sudo -u aipo_posgres postgres/bin/pg_dump org001 > backup/org001.sql
```
ダンプできたら移行先サーバーへアップしておきましょう。

### 移行先でDB入れ替え
AIPOは停止状態であること（Postgresプロセスが停止していること）

```:data削除
$ cd /usr/local/aipo/postgres
$ sudo -rf data
$ sudo mkdir data
$ sudo chown -R aipo_postgres. data
$ sudo chmod -R 700 data
```
```:DB初期化
$ cd /usr/local/aipo
$ sudo -u aipo_postgres postgres/bin/initdb --encoding=UTF8 --no-locale --pgdata=/usr/local/aipo/postgres/data
```
```:postgres process起動
$ cd /usr/local/aipo
$ sudo -u aipo_postgres postgres/bin/postgres -D /usr/local/aipo/postgres/data &
```
```:DB作成(DB: org001, オーナー: aipo_postgres)
$ cd /usr/local/aipo
$ sudo -u aipo_postgres postgres/bin/createdb org001 -O aipo_postgres
```
```:DB data(org001.sql)をインポート
～ パス/〇〇 に おいてあるとする
$ sudo postgres/bin/psql -U aipo_postgres -d org001 -f /〇〇/org001.sql
```
```:postgres process停止
$ cd /usr/local/aipo
$ sudo -u aipo_postgres postgres/bin/pg_ctl -D /usr/local/aipo/postgres/data stop
```
## Tomcat コネクター変更(80 ⇒ 8080)
この後に Apacheをいれるので 80ポートがぶつからないように ポートを変更します。
```:server.xml
$ cd /usr/local/aipo
$ sudo vi tomcat/conf/server.xml

===== 修正前：80コネクターの場所
<Connector port="80" maxThreads="1000" protocol="org.apache.coyote.http11.Http11NioProtocol"
               connectionTimeout="20000"
               redirectPort="8443" />
=====
===== 修正後：80 ⇒ 8080
<Connector port="8080" maxThreads="1000" protocol="org.apache.coyote.http11.Http11NioProtocol"
               connectionTimeout="20000"
               redirectPort="8443" />
=====
```
```:Tomcat再起動
$ cd /usr/local/aipo
$ sudo tomcat/bin/shutdown.sh
$ sudo tomcat/bin/startup.sh
```


## Apacheを入れる
```
$ sudo dnf install httpd -y

$ sudo vi /etc/httpd/conf.d/aipo.conf

tomcat と ajp通信(8009)でリバーシプロキシをさせます。
ServerNameのところは適時読み替えてください。
=====新規====
<VirtualHost *:80>
  DocumentRoot /var/www/html
  ServerName www.xxxxxxxx.xxx

  RewriteEngine On
  ProxyRequests Off
  ProxyPreserveHost On
  AddDefaultCharset off

  ProxyPass        /aipo/  ajp://localhost:8009/aipo/
  ProxyPassReverse /aipo/  ajp://localhost:8009/aipo/
  ProxyPass        /gadgets/   ajp://localhost:8009/gadgets/
  ProxyPassReverse /gadgets/  ajp://localhost:8009/gadgets/

  ErrorLog logs/aipo_error_log
  TransferLog logs/aipo_access_log
</VirtualHost>
=============

$ sudo systemctl start httpd
```

## AIPO起動(AIPO7)

```
$ cd /usr/local/aipo
$ sudo bin/startup.sh
```

http://(HostIP)/aipo/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/1e788da4-e03d-af01-fe37-f8882327e241.png)


## ログインしてみる

移行元AIPOのユーザでログイン可能です。
ログインすると、ユーザのアバターが「表示不可」になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/0ef7b735-653a-316e-0235-f254bd487c1d.png)

## エラーログを見る

```:aipo_error_log
$ sudo vi /var/log/httpd/aipo_error_log
(抜粋)
AH02429: Response header name 'Expires ' contains invalid characters, aborting request　～～
```

AH02429エラーが多発しています。これは次のとおりの意味です。

```
レスポンスヘッダーの Expires の後に余計な半角スペースがある。
Apacheはリバーシプロキシを通さない。
```
## エラーの解説

画像を返すとき Expires :～～ となっているようです( コロンの前に余分な半角スペース）
これに対処するには余分な半角スペースを除去する必要があります。
AIPO7のアプリケーション側を修正して Expires: とする必要がありますが、修正をするJavaソースを入手しても「提供元と同じ開発環境を作る」自信がないのでこの対応は事実上無理そうです。できたとしてもテストに半端ない労力を要しそうです。
また、Apache側で細工をして 'Expires 'の画像データを通すようにする方法は見つかっていません（そんなことはできなそう）。

## apache-cve-2016-8743
余計な半角スペースを許さない問題はApacheアップデートに起因しています（DSA 3796-1）
関連記事を載せておきますので興味があるかたは見てくださいね。
https://blog.tigertech.net/posts/apache-cve-2016-8743/
https://lists.debian.org/debian-security-announce/2017/msg00049.html
https://httpd.apache.org/security/vulnerabilities_22.html

これらの記事によると、CVE-2016-8743 は Responseヘッダーに不適切文字列を紛れ込ませることでセキュリティ上の問題を生じてしまうバグの件です。このバグは 2016/12/10 に対応修正版が公開されており、2.2.15 にも取り込まれている様子です。そういえば移行元AIPO7で使うApacheは2.2.15であり、このAIPOでも同じ現象が起きていました( イケてない+言えない方法でごまかしましたけど)

昔 Aipo7 (apache2+tomcat)を構築したときの Apacheバージョンは Apache 2.2.15 ( Build 2017/10/19 )
Aipo7 は 2015年にはリリースされているみたいですので、その時点では、Response Headerに誤り有りでもApacheが許していたのでしょうね。年月が経つのは早いものです。

## Apacheを使う上での結論

Apacheでのリバースプロキシで AIPO7は使えない！

# NginxでAIPO7を使ってみる(ProxyPass)

Apacheを停止（または削除）して、Nginxを起動して試してみましょう。

## Apache停止
```
$ sudo systemctl stop httpd
```

## Nginx インストール
```
$ sudo dnf install nginx -y
```
```:/etc/nginx/conf.d/aipo.conf
$ sudo vi /etc/nginx/conf.d/aipo.conf
===新規（ server_nameは適時読み替えてください）
server {
  listen       80;
  # Host URL or Host IP
  server_name  xxxxxxxxx;
  location / {
     root     /usr/share/nginx/html;
     index   index.html index.htm;
  }
  location /aipo/ {
     root    /usr/share/nginx/html;
     proxy_pass       http://127.0.0.1:8080/aipo/   ;
     # Proxy headers
     proxy_set_header Upgrade           $http_upgrade;
     proxy_set_header Connection        "upgrade";
     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_set_header X-Forwarded-Proto $scheme;
     proxy_set_header X-Forwarded-Host  $host;
     proxy_set_header X-Forwarded-Port  $server_port;


  }
  location /gadgets/ {
     root    /usr/share/nginx/aipo7;
     proxy_pass http://127.0.0.1:8080/gadgets/;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header X-Forwarded-Proto $scheme;
  }
}
===
```

## Nginx 起動

```
sudo systemctl start nginx
```
ちゃんと画像を表示しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/85cef6d1-2ba4-7f3e-a088-7245193faee6.png)

# 最終結論

AIPO8 ⇒ AIPO7 の置き換えを行い、WebサーバーにはNginxを使うのであれば、CentOS9でも 比較的簡単に『AIPO7』を使うことができそうです。

Nginx はApacheと比べてセキュリティ要件が緩いのでしょうか。

今後、Nginxのセキュリティチェックが厳しくなり、Response Header の不当文字(空白混入など）を許さなくなる可能性は将来的にあるかもしれませんが、当面はNginxで大丈夫そうですね。( 2024/11/1 現在 )

AIPO8でAIPO7を使う(Nginxで) の組み合わせはよさげです！ということをこの記事での結論としてみたいと思います。

なお、やっぱり動かないじゃねーか！実害が生じた！というクレームは一切受け付けませんので 自己責任でご利用くださいませ。将来的に ApacheやNginxがどのようにアップグレードされていくのかは私にはわかりませんので。