---
tags: 主機管理, PHP, Apache
---
:::info
[快速linux指令教學(mac, windows, ubuntu...等等適用)|工程師必備技能](https://youtu.be/-fzO7iWCSWY?si=nf-GIgxT4zW8x7z7)
[伺服器架設篇目錄 - RockyLinux 9](https://linux.vbird.org/linux_server/rocky9/)
[Linux 基礎學習訓練教材 - RockyLinux 9.x](https://linux.vbird.org/linux_basic_train/rockylinux9/)
:::
# RockyLinux 9 安裝Apache、PHP8筆記
## 基本設定
* 安裝環境(OS發行版本)

* 預設安裝OpenSSL v3

* 設定主機名稱(假設為Rocky)
```bash
hostnamectl set-hostname Rocky
hostname Rocky
```
* 設定IP
> [nmcli指令設定網卡](https://dywang.csie.cyut.edu.tw/dywang/rhel7/node22.html)
> [nmcli指令說明書](https://networkmanager.dev/docs/api/latest/nmcli.html)
> [Linux 使用 nmcli 指令新增刪除修改網卡 IP](https://ssorc.tw/8749/linux-use-nmcli-commandline-add-delete-ethernet-ip/)
* 先確認網卡名稱:`ip link show`
* 假設有兩張網卡,分別為`ens192`、`ens224`
* 假設一張網卡`ens192`對外網(對外連網),一張網卡`ens224`對內網(用來接NFS Storage)
* 設定外網(ens192),設定IP為`140.130.*.*`及預設閘道`140.130.*.254`
```bash!
nmcli con add type ethernet ifname ens192 con-name ens192 ipv4.addresses 140.130.*.*/24 ipv4.gateway 140.130.*.254 ipv4.dns "140.130.1.20,140.130.1.2" ipv4.method manual
```
* 確認外網(ens192)設定
```bash
nmcli con show ens192
```
* 設定內網(ens224),設定IP為`10.0.0.*`,這張網卡**僅用於內部連接 NFS**,因此不需要設定閘道,避免影響主要網卡的路由。
```bash!
nmcli con add type ethernet ifname ens224 con-name ens224 ipv4.addresses 10.0.0.*/24 ipv4.method manual
```
* 確認內網(ens224)設定
```bash
nmcli con show ens224
```
* 設定路由確保外網優先
```bash
nmcli con modify ens192 ipv4.routes "0.0.0.0/0 140.130.*.*"
nmcli con modify ens224 ipv4.routes "10.0.0.0/24 10.0.0.*"
```
* 重跑網路: `systemctl restart NetworkManager`
* 確認網路狀態
```bash
ip a
ip r
```
* 停用ipv6
```bash
sysctl net.ipv6.conf.all.disable_ipv6=1
sysctl net.ipv6.conf.default.disable_ipv6=1
```
* 在家目錄新增 `.vimrc`
```
set nu
set tabstop=4
```
## 套件更新/基本套件
* 更新現有套件到最新
```bash
yum upgrade --refresh
```
* 安裝及啟用第三方repo
```bash
yum config-manager --set-enabled crb
yum install https://rpms.remirepo.net/enterprise/remi-release-9.rpm
yum config-manager --set-enabled remi
```
* 安裝wget
```bash
yum install wget
```
* 如果在主機會使用到`nslookup`指令,就要安裝`bind-utils`
```bash
yum install bind-utils
```
## SSH設定/校時/防毒
* SSH服務設定調整
```bash
# TWGCB01-012-0044
# DEFAULT:預設全系統加密原則。允許使用 TLSv1.2與 1.3 協定,以及 IKEv2 與SSH2 協定,要求 RSA 密鑰與 Diffie-Hellman 金鑰至少為 2,048 位元
# FUTURE:採取保守之安全原則,可承受近期相關攻擊,不允許使用 SHA-1 演算法,要求 RSA 密鑰與Diffie-Hellman 金鑰至少為3,072 位元
# 查看原設定值為 DEFAULT
cat /etc/crypto-policies/config
# 執行下列指令改為 FUTURE
update-crypto-policies --set FUTURE
update-crypto-policies
```
- 記錄 sshagent 程序使用情形: `vim /etc/audit/rules.d/audit.rules`
```
## TWGCB01-012-0163
-a always,exit -F path=/usr/bin/sshagent -F perm=x -F auid>=1000 -F auid!=4294967295 -k privilegedssh
```
- [Fail2ban](https://net.nthu.edu.tw/netsys/security:fail2ban)
* [How To Protect SSH with Fail2Ban on Rocky Linux 9](https://www.digitalocean.com/community/tutorials/how-to-protect-ssh-with-fail2ban-on-rocky-linux-9)
* 校時設定
> 在 CentOS 8 預設已經沒有 ntpdate 來做系統校時,改用 chrony 來完成系統校時的工作。chrony 是一個 NTP Client/Server 並存的套件 。
* 將原來的chrony.conf設定檔備一份下來
```bash
cp /etc/chrony.conf /etc/chrony.conf_bak
```
* 修改 /etc/chrony.conf,只留下列資訊 (`vi /etc/chrony.conf`)
```
server 140.130.1.254 iburst
```
* 重起chronyd服務
```bash
systemctl restart chronyd
```
* 立即校時指令
```bash
chronyc -a makestep
```
* 查看詳細的校時資訊
```bash
chronyc tracking
chronyc sources -v
```
* 安裝防毒軟體clamav
> [參考文件](https://blog.maxkit.com.tw/2021/05/install-clamav-in-centos-7.html)
* 安裝
```bash
# 安裝
yum install -y clamav clamd clamav-update
sudo setsebool -P antivirus_can_scan_system on
# 配置文件刪除 Example 字符串
sed -i -e "s/^Example/#Example/" /etc/clamd.d/scan.conf
sed -i -e "s/^Example/#Example/" /etc/freshclam.conf
```
* 建立的log檔
```bash
mkdir -p /var/log/clamav
chown -R clamupdate:clamupdate /var/log/clamav/
mkdir -p /var/log/clamd/
touch /var/log/clamd/clamd.scan
chown -R clamscan:clamscan /var/log/clamd
```
* 更新配置文件 `/etc/freshclam.conf`
```
# 增加下面一條台灣的mirror site
DatabaseMirror db.tw.clamav.net
```
* 調整配置設定 `/etc/clamd.d/scan.conf`
```
# 啟用紀錄
LogFile /var/log/clamd/clamd.scan
# 啟用LocalSocket
LocalSocket /var/run/clamd.scan/clamd.sock
# 啟用記錄訊息時間
LogTime yes
# 啟用ExtendedDetecionInfo
ExtendedDetectionInfo yes
# 啟用PidFile
PidFile /var/run/clamd.scan/clamd.pid
```
* 更新病毒碼
```bash
# 更新病毒碼
freshclam
# 查詢病毒碼版本
clamscan --version
```
* 啟用服務
```bash
systemctl start clamd@scan
systemctl enable clamd@scan
systemctl status clamd@scan
## on-access scanning
systemctl start clamonacc
systemctl enable clamonacc
```
* 設定自動更新病毒碼,建立一個批次檔 `/etc/cron.daily/freshclam.sh` (如下) 讓crontab跑
```bash
#!/bin/bash
freshclam --quiet -l /var/log/clamav/freshclam.log
```
* 設定批次檔權限
```bash
chmod 755 /etc/cron.daily/freshclam.sh
```
* 手動掃描
```bash
# 掃檔案
clamscan filename
# 掃目錄
clamscan -r directoryname
```
## 安裝HTTP
* 安裝 Apache
```bash
yum install httpd httpd-tools mod_ssl -y
httpd -v
systemctl start httpd
systemctl enable httpd
```

## 安裝PHP
* [PHP Release Cycle Update](https://php.watch/news/2024/09/php-release-cycle-updates)
* 安裝 oracle instant client

> #9 – 11.2.0.3 or 11.2.0.4 only. For Oracle Autonomous Transaction Processing and Oracle Autonomous Data Warehouse, there is additional limitation and 11.2.0.4 is the minimum supported client version.
> #12 – 12.1.0.2 only. For 11.2 interoperability, 11.2.0.4 is required.
> Client-server version interoperability is detailed in [Doc ID 207303.1](https://support.oracle.com/epmos/faces/DocumentDisplay?id=207303.1). Oracle Call Interface 23 can connect to Oracle Database 19c or later, while Oracle Call Interface 19.3 can connect to Oracle Database 11.2 or later. Some tools may have other restrictions.
> [PHP 8.2.26 起有安裝限制,必 >= 23.1](https://www.rpmfind.net/linux/RPM/remi/enterprise/8/x86_64/php82-php-oci8-8.2.26-1.el8.remi.x86_64.html)
* 安裝指令
```bash
wget https://download.oracle.com/otn_software/linux/instantclient/2390000/oracle-instantclient-basic-23.9.0.25.07-1.el9.x86_64.rpm
wget https://download.oracle.com/otn_software/linux/instantclient/2390000/oracle-instantclient-devel-23.9.0.25.07-1.el9.x86_64.rpm
yum install oracle-instantclient-basic-23.9.0.25.07-1.el9.x86_64.rpm --nogpgcheck -y
yum install oracle-instantclient-devel-23.9.0.25.07-1.el9.x86_64.rpm --nogpgcheck -y
yum list installed | grep oracle
```
* 設定oracle環境參數
> vi /etc/profile.d/client.sh
```bash
export PHP_DTRACE=yes
export ORACLE_HOME=/usr/lib/oracle/23.9/client64
export PATH=$PATH:$ORACLE_HOME/bin
export LD_LIBRARY_PATH=$ORACLE_HOME/lib
export TNS_ADMIN=$ORACLE_HOME/network/admin
```
* 確認設定生效
```bash
> sh /etc/profile.d/client.sh
> source /etc/profile.d/client.sh
> echo $ORACLE_HOME
```
* 安裝PHP
* 查看可以安裝的PHP版本
```bash
yum module list php
```

* 設定預設要安裝的PHP版本
```bash
yum module enable php:remi-8.3 -y
```

* 安裝指令
> php-zip在php7.4時被移到pecl裡,改安裝php-pecl-zip,是PhpSpreadsheet必要的延伸安裝
> php-oci8在php8.4時被移到pecl裡,改安裝php-pecl-oci8
> [PHP 8.4: OCI8 and PDO-OCI extensions from PHP Core to PECL](https://php.watch/versions/8.4/oci8-pdo_oci-unbundled)
> 在 RHEL 7 或以前的版本, 預設會使用 mod_php 配合 Apache 執行, 從 RHEL 8 開始會預設使用 PHP-FPM 執行 PHP, 所以需要啟動 PHP-FPM
>
```bash
yum install php php-fpm
# <= php8.3
yum install php-soap php-oci8 php-bcmath php-devel php-gd php-ldap php-mysqlnd
yum install php-pecl-zip
# >= php8.4
yum install php-soap php-bcmath php-devel php-gd php-ldap php-mysqlnd
yum install php-pecl-zip php-pecl-oci8
systemctl start php-fpm
systemctl enable php-fpm
systemctl restart httpd
```
* 安裝composer套件管理指令工具
```bash
wget https://getcomposer.org/installer -O composer-installer.php
php composer-installer.php --filename=composer --install-dir=/usr/local/bin
composer --version
```

## 安全性設定調整
> [SELinux 初探](https://linux.vbird.org/linux_server/rocky9/0140selinux.php)
> [The Apache HTTP Server and SELinux](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/7/html/selinux_users_and_administrators_guide/chap-managing_confined_services-the_apache_http_server)
> [Sharing NFS and CIFS volumes](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/7/html/selinux_users_and_administrators_guide/sect-managing_confined_services-the_apache_http_server-configuration_examples#sect-Managing_Confined_Services-Configuration_examples-Sharing_NFS_and_CIFS_file_systems)
> 
* 防火牆設定
```bash
# SELinux設定
setsebool -P httpd_can_network_connect on
# 如果有掛載storage
setsebool -P httpd_use_nfs on
# 加上http和https開放設定
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
# 重新載入
firewall-cmd --reload
# 查看規則
firewall-cmd --list-all
```
* 遇到自定義上傳檔案的資料夾,要額外下指令設定
> [Configuring SELinux Policies for Apache Web Servers](https://www.serverlab.ca/tutorials/linux/web-servers-linux/configuring-selinux-policies-for-apache-web-servers/)
```bash
chcon -R -t httpd_sys_rw_content_t <資料夾路徑>
# Laravel專案內需要額外針對storage資料夾進行設定
cd <laravel_project_path>
chcon -R -t httpd_sys_rw_content_t storage
```
* 在 `/var/www/html/` 內新增 `info.php`,驗證PHP安裝結果。

* 驗證完後,記得把info.php刪掉。
* 設定調校
* 在 `/etc/php.ini` 做設定調整
```
expose_php = Off
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE & ~E_WARNING
date.timezone = Asia/Taipei
session.cookie_httponly = 1
session.cookie_samesite = "Lax"
# 下面這行原本有註解,要去註解啟用它
error_log = php_errors.log
```
* 在 `/etc/httpd/conf/httpd.conf`、`/etc/httpd/conf.d/vhost.conf` 等設定檔,做開放資料夾權限設定調整
```conf
Options -Indexes +FollowSymLinks
```
* 新增 `/etc/httpd/conf.d/security.conf` 檔案
```conf
# set up response header
<IfModule mod_headers.c>
# 隱藏 Apache、PHP 版本
Header unset Server
RequestHeader unset Server
Header always unset X-Powered-By
Header unset X-Powered-By
Header unset X-CF-Powered-By
Header unset X-Mod-Pagespeed
Header unset X-Pingback
# 增加隱私權
# Referrer 代表的是你從 A 網站跳到 B 網站的時候,這個欄位會被記錄為 A
# 簡單來說,他是記錄你上一個瀏覽的地方的東西
Header set Referrer-Policy: "no-referrer"
# 防禦 Clickjacking 攻擊
# 防止釣魚網站透過iframe來嵌入自己的網站
# 政府組態 TWGCB-04-005-0036
Header always append X-Frame-Options SAMEORIGIN
Header always append Frame-Options SAMEORIGIN
# IE8+ and variants, XSS Protection
Header always append X-XSS-Protection "1;mode=block"
# Protection from drive-by dynamic/executable IE files
# 避免瀏覽器誤判文件形態
# X-Content-Type-Options 是拿來防止 Content-Type 被竄改
# 比較要注意的是,這個屬性只會套用在 script style
Header always append X-Content-Type-Options "nosniff"
# cookie設定
Header always edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure;SameSite=Lax
Header set Cache-Control "no-cache=\"Set-Cookie\""
# 隱藏Etag資訊
Header unset ETag
FileETag None
</IfModule>
# Apache Range Exploit
RequestHeader unset Range
RequestHeader unset Request-Range
# 隱藏Apache版本
# 政府組態 TWGCB-04-005-0048
ServerTokens Prod
# 政府組態 TWGCB-04-005-0049
ServerSignature Off
#關閉HTTP TRACE 避免Cross Site Scripting風險
# 政府組態 TWGCB-04-005-0030
TraceEnable Off
```
* httpd的設定調校後,可以執行 `apachectl configtest` 指令看看有沒有設定錯誤的地方。
* 相關設定完後,請執行 `systemctl restart httpd` 重跑服務。
* 部署 https
* 確認環境

* 利用 [SSL Configuration Generator](https://ssl-config.mozilla.org/) 產生 ssl.conf 設定內容
* [產生的設定內容](https://ssl-config.mozilla.org/#server=apache&version=2.4.57&config=intermediate&openssl=3.0.7&guideline=5.7)
* 將產生的內容,經過整理貼到 `/etc/httpd/conf.d/ssl.conf` 去。
* 設定https後,重跑服務遇到 `SSLCertificateKeyFile: file '/etc/httpd/2022_SSL/xxx.cer' does not exist or is empty` 的解決方式 ([參照](https://serverfault.com/questions/416612/apache-sslcertificatekeyfile-file-does-not-exist-or-is-empty)):
```bash
restorecon -Rv /etc/httpd/2022_SSL/
```
* ==Laravel專案移機部署要特別留意 `.env` 檔中的 `APP_URL`==,如果 `.env` 檔跟 `httpd.conf` 設定檔兩邊的domain name沒有一致,容易發生404系列的錯誤。
* 修改 httpd 的設定,要重跑 httpd 服務 (`systemctl restart httpd`)。
* 修改 php.ini 的設定,則要重跑 php 服務 (`systemctl restart php-fpm`)。
* 其他紀錄
```bash
composer config -g -- secure-http false
composer config -g -- disable-tls true
```
## PHP升級方式
* 若是從PHP8.2(含)以下版本,升級至PHP8.3(含)以上者,先確認Oracle instant client是否有升級至23.1以上版本。
* 升級指令如下:
```bash
dnf module reset php -y
dnf module enable php:remi-8.3 -y
yum update php -y
systemctl restart php-fpm
php -v
```