OracleCloud（A1.Flex）やRaspberry PiにPHP8.1をインストール

# はじめに

ARM で PHP8.1 をセルフビルドして、Nginx と共に動かす方法です。
DNF コマンドで PHP を入れると古い、あるいはパッケージが取得できない場合に当記事の方法が有効です。
Raspberry Pi も同様の手順で出来るはずです。

# 環境

* OCI Oracle Cloud / Ampere A1
* Oracle Linux 8 （CentOS, Fedora など RHEL 系ならどれでも可）

# 建てるもの

* Nginx
* PHP 8.1
* MySQL

# 実際に建てる

## リポジトリ有効化

```console
# dnf repolist all
repo id                                repo name                                                            status
ol8_MySQL80                            MySQL 8.0 for Oracle Linux 8 (aarch64)                               enabled
ol8_MySQL80_connectors_community       MySQL 8.0 Connectors Community for Oracle Linux 8 (aarch64)          enabled
ol8_MySQL80_tools_community            MySQL 8.0 Tools Community for Oracle Linux 8 (aarch64)               enabled
ol8_aarch64_userspace_ksplice          Ksplice aware userspace packages for Oracle Linux 8 (aarch64)        disabled
ol8_addons                             Oracle Linux 8 Addons (aarch64)                                      enabled
ol8_appstream                          Oracle Linux 8 Application Stream (aarch64)                          enabled
ol8_baseos_latest                      Oracle Linux 8 BaseOS Latest (aarch64)                               enabled
ol8_codeready_builder                  Oracle Linux 8 CodeReady Builder (aarch64) - Unsupported             enabled
ol8_developer                          Oracle Linux 8 Development Packages (aarch64)                        disabled
ol8_developer_EPEL                     Oracle Linux 8 EPEL Packages for Development (aarch64)               enabled
ol8_developer_UEKR6                    Developer Preview of UEK Release 6 (aarch64)                         disabled
ol8_distro_builder                     Oracle Linux 8 Distro Builder (aarch64) - Unsupported                disabled
ol8_ksplice                            Ksplice for Oracle Linux 8 (aarch64)                                 enabled
ol8_kvm_appstream                      Oracle Linux 8 KVM Application Stream (aarch64)                      disabled
ol8_oci_included                       Oracle Software for OCI users on Oracle Linux 8 (aarch64)            enabled
ol8_u2_baseos_base                     Oracle Linux 8.2 BaseOS (aarch64)                                    disabled
ol8_u3_baseos_base                     Oracle Linux 8.3 BaseOS (aarch64)                                    disabled
ol8_u4_baseos_base                     Oracle Linux 8.4 BaseOS (aarch64)                                    disabled

# dnf config-manager --enable ol8_developer_EPEL
# dnf config-manager --enable ol8_codeready_builder
# dnf upgrade
```

Oracle Linux 以外の RHEL 系を使っている場合も、同様の手順で
EPEL と PowerTools または codeready-builder のリポジトリを有効化します。

## Nginx をインストール

### インストール

```console
# dnf -y install nginx
# vi /usr/lib/systemd/system/nginx.service
```
```vim:nginx.service
[Service]
Type=forking
LimitNOFILE=65535 // 修正
```
```console
# systemctl daemon-reload
```

### SELinux の修正

* .teファイルを作成する
* .teファイルから.modファイルを作成する
* .modファイルからバイナリの.ppファイルを作成する
* .ppファイルをsemoduleに読み込ませてSELinuxのポリシーに追加する


```console
# vi nginx-passenger.te
```

```vim:nginx-passenger.te
module nginx-passenger 1.0;

require {
        type var_run_t;
        type user_home_dir_t;
        type httpd_t;
        type user_home_t;
        type httpd_tmp_t;
        type httpd_tmpfs_t;
        type passenger_exec_t;
        type postgresql_port_t;
        type httpd_log_t;
        type httpd_sys_content_t;
        type postfix_etc_t;
        type var_log_t;
        type root_t;
        type etc_runtime_t;
        type fusefs_t;
        type default_t;
        type http_cache_port_t;
        type unreserved_port_t;
        type unconfined_t;
        type admin_home_t;
        type system_mail_t;
        type httpd_sys_rw_content_t;
        class process execmem;
        class capability { fowner sys_resource fsetid sys_ptrace };
        class tcp_socket name_connect;
        class shm { associate getattr read unix_read unix_write write destroy };
        class file { execute setattr read create execute_no_trans write ioctl open append map };
        class capability2 block_suspend;
        class process ptrace;
        class process setrlimit;
        class file { ioctl write execute setattr read rename create open execute_no_trans getattr lock};
        class lnk_file { read getattr write open };
        class dir { write search read create open getattr add_name };
        class sock_file write;
}

#============= httpd_t ==============

allow httpd_t httpd_tmp_t:file execute;
allow httpd_t httpd_tmpfs_t:file execute;
allow httpd_t httpd_log_t:file setattr;
allow httpd_t passenger_exec_t:dir { search getattr };
allow httpd_t self:capability sys_ptrace;
allow httpd_t self:process ptrace;
allow httpd_t self:process execmem;
allow httpd_t self:capability2 block_suspend;
allow httpd_t user_home_t:file { execute execute_no_trans read open write };
allow httpd_t var_run_t:file { read write };
allow httpd_t postfix_etc_t:file { read getattr open };
allow httpd_t root_t:dir write;
allow httpd_t root_t:dir add_name;
allow httpd_t root_t:file create;
allow httpd_t root_t:file { open read write };
allow httpd_t root_t:file lock;
allow httpd_t etc_runtime_t:file write;
allow httpd_t fusefs_t:file { getattr read open write };
allow httpd_t fusefs_t:dir { read write };
allow httpd_t user_home_t:lnk_file { read write open };
allow httpd_t default_t:lnk_file { read write open };
allow httpd_t default_t:file { read write open };
allow httpd_t http_cache_port_t:tcp_socket name_connect;
allow httpd_t unreserved_port_t:tcp_socket name_connect;
allow httpd_t admin_home_t:file getattr;
allow system_mail_t httpd_sys_rw_content_t:file { read write };
allow httpd_t unconfined_t:shm { unix_read unix_write associate getattr read write destroy };
allow httpd_t self:process setrlimit;
allow httpd_t var_log_t:file open;
allow httpd_t root_t:file map;
allow httpd_t var_run_t:sock_file write;
```

```console
# checkmodule -M -m -o nginx-passenger.mod nginx-passenger.te
# semodule_package -o nginx-passenger.pp -m nginx-passenger.mod
# semodule -i nginx-passenger.pp
```

## PHP8.1 をビルドしてインストールする

```console
# dnf install -y gcc-c++ libxslt-devel sqlite-devel bzip2-devel gd-devel oniguruma-devel libzip-devel openssl-devel curl-devel libsodium libsodium-devel libicu-devel
# mkdir -p /root/pkg
# cd /root/pkg
# wget --no-check-certificate https://www.php.net/distributions/php-8.1.6.tar.gz
# tar zxvf php-8.1.6.tar.gz
# cd php-8.1.6
# ./configure --prefix=/usr/local/php-8.1.6 \
--with-config-file-path=/etc \
--enable-soap --with-zlib-dir --with-iconv \
--enable-mbstring --with-zip --enable-exif \
--enable-gd --with-external-gd --with-zlib \
--with-webp --with-jpeg --with-bz2 \
--with-libxml --enable-gd-jis-conv  \
--with-freetype --with-xpm \
--enable-sockets --with-openssl  \
--with-gettext --enable-sigchild \
--enable-opcache --enable-fpm \
--with-fpm-user=nginx --with-fpm-group=nginx \
--with-pdo_mysql --with-curl --enable-exif \
--enable-bcmath --enable-mbstring=all \
--enable-pcntl --enable-intl --with-sodium \
--enable-mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd

～　略　～

+--------------------------------------------------------------------+
| License:                                                           |
| This software is subject to the PHP License, available in this     |
| distribution in the file LICENSE. By continuing this installation  |
| process, you are bound by the terms of this license agreement.     |
| If you do not agree with the terms of this license, you must abort |
| the installation process at this point.                            |
+--------------------------------------------------------------------+

Thank you for using PHP.

# make;make install

～　略　～

Build complete.
Don't forget to run 'make test'.

Installing shared extensions:     /usr/local/php-8.1.6/lib/php/extensions/no-debug-non-zts-20210902/
Installing PHP CLI binary:        /usr/local/php-8.1.6/bin/
Installing PHP CLI man page:      /usr/local/php-8.1.6/php/man/man1/
Installing PHP FPM binary:        /usr/local/php-8.1.6/sbin/
Installing PHP FPM defconfig:     /usr/local/php-8.1.6/etc/
Installing PHP FPM man page:      /usr/local/php-8.1.6/php/man/man8/
Installing PHP FPM status page:   /usr/local/php-8.1.6/php/php/fpm/
Installing phpdbg binary:         /usr/local/php-8.1.6/bin/
Installing phpdbg man page:       /usr/local/php-8.1.6/php/man/man1/
Installing PHP CGI binary:        /usr/local/php-8.1.6/bin/
Installing PHP CGI man page:      /usr/local/php-8.1.6/php/man/man1/
Installing build environment:     /usr/local/php-8.1.6/lib/php/build/
Installing header files:          /usr/local/php-8.1.6/include/php/
Installing helper programs:       /usr/local/php-8.1.6/bin/
  program: phpize
  program: php-config
Installing man pages:             /usr/local/php-8.1.6/php/man/man1/
  page: phpize.1
  page: php-config.1
/root/pkg/php-8.1.6/build/shtool install -c ext/phar/phar.phar /usr/local/php-8.1.6/bin/phar.phar
ln -s -f phar.phar /usr/local/php-8.1.6/bin/phar
Installing PDO headers:           /usr/local/php-8.1.6/include/php/ext/pdo/
```


### Imagick をビルドしてインストールする

```console
# dnf install -y ImageMagick-devel autoconf
# wget --no-check-certificate https://pecl.php.net/get/imagick-3.7.0.tgz
# tar zxvf imagick-3.7.0.tgz

# cd imagick-3.7.0/
# /usr/local/php-8.1.6/bin/phpize 
Configuring for:
PHP Api Version:         20210902
Zend Module Api No:      20210902
Zend Extension Api No:   420210902

# ./configure --with-php-config=/usr/local/php-8.1.6/bin/php-config

creating libtool
appending configuration tag "CXX" to libtool
configure: patching config.h.in
configure: creating ./config.status
config.status: creating config.h


# make; make install

～　略　～

----------------------------------------------------------------------
Libraries have been installed in:
   /home/opc/imagick-3.7.0/modules

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH' environment variable
     during linking
   - use the `-Wl,--rpath -Wl,LIBDIR' linker flag
   - have your system administrator add LIBDIR to `/etc/ld.so.conf'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------

Build complete.
Don't forget to run 'make test'.

Installing shared extensions:     /usr/local/php-8.1.6/lib/php/extensions/no-debug-non-zts-20210902/
Installing header files:          /usr/local/php-8.1.6/include/php/

```

### 拡張を追記する

```console
# ls -al /usr/local/php-8.1.6/lib/php/extensions/no-debug-non-zts-20210902/
total 5112
drwxr-xr-x. 2 root root      42 Sep 16 07:52 .
drwxr-xr-x. 3 root root      39 Sep 11 10:06 ..
-rwxr-xr-x. 1 root root 1621448 Sep 16 07:52 imagick.so
-rwxr-xr-x. 1 root root 3609728 Sep 11 10:06 opcache.so

# cp /root/pkg/php-8.1.6/php.ini-production /etc/php.ini
# vi /etc/php.ini
```


```vim:php.ini
// ▼ コメント解除して変更

extension_dir = "/usr/local/php-8.1.6/lib/php/extensions/no-debug-non-zts-20210902/"

date.timezone = Asia/Tokyo
expose_php = Off
post_max_size = 500M
upload_max_filesize = 200M
memory_limit = 512M

[opcache]
zend_extension=opcache.so
opcache.enable=1
opcache.memory_consumption=192
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.revalidate_path=1
opcache.dups_fix=1
opcache.enable_file_override=1
opcache.enable_cli=0

// ▼ 追記

[imagick]
extension=imagick.so
```

### PHP の設定を確認

```console
# cd /usr/local/
# ln -s php-8.1.6 php
# cd /usr/local/php/bin
# ./php -v
PHP 8.1.6 (cli) (built: May 16 2022 06:09:27) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.6, Copyright (c) Zend Technologies
    with Zend OPcache v8.1.6, Copyright (c), by Zend Technologies
```

OPcache の拡張が読み込めていれば完了。


## Nginx と PHP の接続

Nginx を PHP-FPM を使って PHP と接続します。プロトコルには TCP を使います。
UDS を使う事もできますが、その場合はさらに SELinux に手を入れる必要があります。

```console
# mkdir -p /var/log/php-fpm/
# cd /usr/local/php/etc
# cp php-fpm.conf.default php-fpm.conf
# vi php-fpm.conf
```

```vim:php-fpm.conf
// ▼ コメントアウトを解除して編集

pid = run/php-fpm.pid
error_log = /var/log/php-fpm/php-fpm.log
log_level = debug
daemonize = yes
include=/usr/local/php-8.1.6/etc/php-fpm.d/*.conf
```

```console
# cd /usr/local/php/etc/php-fpm.d
# cp www.conf.default www.conf
# vi www.conf
```


```vim:www.conf

# ▼ デフォルト値のままでよい（異なっていれば編集）

[www]
user = nginx
group = nginx
listen = 9000

# ▼ 編集、またはコメントアウトを解除して編集

pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 40
pm.max_requests = 500

access.log = /var/log/php-fpm/$pool.access.log 
access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%" 
slowlog = /var/log/php-fpm/$pool.log.slow 
request_slowlog_timeout = 1 
catch_workers_output = yes 
php_admin_value[error_log] = /var/log/php-fpm/$pool.error.log  
php_admin_flag[log_errors] = on 
```

### PHP-FPM をサービスに登録する

```console
# cd /root/pkg/php-8.1.6/sapi/fpm 
# cp php-fpm.service /etc/systemd/system/php-fpm.service 
# vi /etc/systemd/system/php-fpm.service 
```

```vi:php-fpm.service
// ▼ 修正
PIDFile=/usr/local/php/var/run/php-fpm.pid 
ExecStart=/usr/local/php/sbin/php-fpm --nodaemonize --fpm-config /usr/local/php/etc/php-fpm.conf 

// ▼ コメントアウト
#ProtectSystem=full 
```

```console
# systemctl daemon-reload
# systemctl enable php-fpm
# systemctl restart php-fpm
```

### Nginx を PHP-FPM に接続する

```console
# vi /etc/nginx/nginx.conf
```

RHEL 8 系（CentOS 8, Oracle Linux 8）ではない場合、ファイルパスは /etc/nginx/conf.d/default.conf である場合があります。

```vim:nginx.conf
http {

    # ～　略　～

    # ▼ 追記する
    upstream backend {
        ip_hash;
        server localhost:9000;
        keepalive 100;
    }

    server {

        # ～　略　～

        # ▼ 編集する
        location / {
            root /usr/share/nginx/index/html;
            index index.html index.htm;
        }

        # ▼ 追記する
        location ~ \.php$ {
            fastcgi_pass backend;   # upstream
            proxy_set_header        Host $http_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-NginX-Proxy true;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            proxy_redirect off;
            fastcgi_intercept_errors on;
            fastcgi_read_timeout 260;
            fastcgi_send_timeout 260;
            proxy_send_timeout 260;
            proxy_read_timeout 260;
            proxy_connect_timeout 260;
        }

    }

}
```

### Firewall に穴をあける

```console
# firewall-cmd --zone=public --permanent --add-port=80/tcp
# firewall-cmd --zone=public --permanent --add-port=443/tcp
# firewall-cmd --reload
```

* OCI の場合、VCN（仮想クラウドネットワーク）のセキュリティルールにも下記を追加すること
 * TCP 80番
 * TCP 443番

### SELinux で許可する

```
# setsebool -P httpd_can_network_connect 1
# chcon -R -h -t httpd_sys_script_rw_t /usr/share/nginx/html/
```



# 動作テスト

* "nginx -t" は config ファイルのテストをするコマンド
 * successful と表示されなければ随時修正すること

```console
# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

# systemctl enable --now nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.
```

* ファイルを作って実際にアクセス

```console
# vi /usr/share/nginx/html/index.php
```

```php:index.php
<?php 
phpinfo();
```

グローバルIPアドレス/index.php にアクセスしてみて PHP INFO が表示されれば完了。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21236/37db09ec-e773-3e95-cd18-d1a94714e5b8.png)




# おまけ

## MySQL

### インストール

```console
# dnf -y install mysql-server mysql mysql-devel
# systemctl enable --now mysqld
Created symlink /etc/systemd/system/multi-user.target.wants/mysqld.service → /usr/lib/systemd/system/mysqld.service.

# vi /usr/lib/systemd/system/mysqld.service
```

```vim:mysqld.service
LimitNOFILE = 65535 // 修正
```

### PHP.ini に mysql.sock のパスを書く

```console
# vi /etc/php.ini
```

```vim:php.ini
[Pdo_mysql]
; Default socket name for local MySQL connects.  If empty, uses the built-in
; MySQL defaults.
pdo_mysql.default_socket=/var/lib/mysql/mysql.sock
```



### SELinux を修正

* .teファイルを作成する
* .teファイルから.modファイルを作成する
* .modファイルからバイナリの.ppファイルを作成する
* .ppファイルをsemoduleに読み込ませてSELinuxのポリシーに追加する

```console
# vi mysql_selinux_allow.te
```

```vim:mysql_selinux_allow.te
module mysql_selinux_allow 1.0;
require {
        type mysqld_t;
        type mysqld_tmp_t;
        type tmp_t;
        type init_t;
        class sock_file create;
        class file unlink;
}
#============= init_t ==============
allow init_t mysqld_tmp_t:file unlink;
#============= mysqld_t ==============
allow mysqld_t tmp_t:sock_file create;
```

```console
# checkmodule -M -m -o mysql_selinux_allow.mod mysql_selinux_allow.te
# semodule_package -o mysql_selinux_allow.pp -m mysql_selinux_allow.mod
# semodule -i mysql_selinux_allow.pp

# setsebool -P httpd_can_network_connect 1
# setsebool -P httpd_can_network_connect_db 1
```

## UDS のためにソケットディレクトリを自動生成させる

```console
vi /usr/lib/tmpfiles.d/php-fpm.conf 
```
```vim:php-fpm.conf
d /run/php-fpm 0755 root root -
```

# 変更履歴

2021-11-10 初稿
2021-11-12 nginx-passenger.te を UDS 対応のものへ差し替え
2021-10-19 mysql.sock のパスを変更する旨を追記
2022-05-16 php 8.1.6 に書き換え、その他