架站筆記
持續更新中 💪
我自己寫了一個 Side Project。 這個 Project 預計就是拿來做面試的火力展示(我就是來玩的 😤)、以及各種我想要幫自己生活自動化、幫助我自己的服務。 例如:
- 詢問黃金價格(目前有自己公開的 API & Line)
- 詢問棒球比賽分數(不過目前用免費的外部 API 有點弱這一塊)
- 查詢空氣品質、查詢目前所在的位置(Line)
- 星座運勢查詢(API & Line)
- 串接 AI 做翻譯、做精簡文字功能 (Prompt Engineering / Line)
目前 Line 帳號只是自己在玩自己在用,我需要多多整理一下另外調整一下 icon 玩一下選單等功能在 Project 開放展示這樣...
順便來學習怎麼自己架設 PHP、Nginx、PostgreSQL、Redis 以及 Ubuntu Server。這個過程中遇到不少挑戰,也累積了不少經驗,未來會持續記錄相關心得與技術細節。
SSH
# /etc/ssh/sshd_config
PermitRootLogin no # 拒絕使用 Root 登入
PasswordAuthentication no # 禁止使用密碼登入
# 可以使用者個指令驗證
# sudo sshd -T | grep passwordauthentication
# 重新啟動 SSH: service sshd restart
Logrotate
- Ubuntu / Debian / CentOS 等主流 Linux 發行版都內建 logrotate
- 以 nginx 為例
cat /etc/logrotate.d/nginx
範例如下:
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid`
endscript
}
| 設定項 | 意義 |
|---|---|
daily | 每天輪替一次 |
rotate 14 | 保留 14 份舊 log(即保留兩週) |
compress | 用 gzip 壓縮舊 log |
delaycompress | 延遲一天再壓縮(避免 Nginx 還在寫) |
notifempty | 若 log 為空則不輪替 |
create | 新 log 的檔案權限與擁有者 |
postrotate ... endscript | 在輪替後通知 nginx 重新打開 log 檔案 |
User
- 不要用 root 執行 Laravel 或部署,建立專用使用者
adduser deployer
安裝基本工具
尚未實作
-
安裝基本監控工具:
sudo apt install htop iotop net-tools vnstat -
若有餘裕,可加上:
- Netdata:即時效能監控(非常輕量)
- Prometheus + Grafana(進階方案)
ufw
- 防火牆
# 看目前狀態:sudo ufw status verbose
ufw allow 22/tcp # SSH
ufw allow 80,443/tcp # HTTP/HTTPS
ufw enable
Cloudflare
- proxy 開啟
- 設定 SSL 開啟 Full (strict) 模式。
- 設定 A record 或 CNAME record (A for IP, CNAME for URL)
Let's Encrypt
sudo apt update
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d $APP_URL
sudo systemctl list-timers | grep certbot # 可以看到有 自動續期設定
應用層
nginx
nginx -t # 可以使用這個指令看看自己 nginx config 有沒有問題
PHP-FPM
- 打開 opcache
# php -i | grep -i opcache
opcache.enable=1
opcache.enable_cli=0 ; CLI 可不啟用
opcache.validate_timestamps=1
opcache.revalidate_freq=2 ; 每 2 秒檢查一次檔案變更
-
設定
fastcgi_read_timeout足夠高(避免 Queue job 超時)。 -
PHP-FPM 建議設定:
pm = dynamic
pm.max_children = 10 # 視記憶體調整
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
設定 Swap 記憶體
free -h # 可以用這個指令看目前狀況
uptime # 看主機 loading
範例:
sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Redis & PostgreSQL(Database)
- 如果有安裝這些,請務必確認是不是只有本機可連線、不要讓別人連線以至於被偷家了
Redis
# grep -E "^(bind|protected-mode)" /etc/redis/redis.conf
# 去 /etc/redis/redis.conf 修改
bind 127.0.0.1 ::1
protected-mode yes
# 或者 sudo ss -tulnp | grep redis
# 應該只能看到 127.0.0.1 或 [::1] 如果是 0.0.0.0 就不行了
Database
sudo grep listen_addresses /etc/postgresql/*/main/postgresql.conf
# 應該是 listen_addresses = 'localhost'
Supervisor
-
每個 Laravel queue 可透過 Supervisor 管理,例如:
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work --sleep=3 --tries=3 --timeout=90
autostart=true
autorestart=true
numprocs=2
user=deployer
redirect_stderr=true
stdout_logfile=/var/log/laravel-worker.log
Laravel
日誌輪替
當設定 LOG_CHANNEL=daily 時,日誌系統會使用每日輪替 (Daily Rotation) 策略。
核心機制
- 輪替 (Rotation): 每天午夜(或首次寫入日誌時),系統會自動停止寫入前一天的檔案,並建立一個帶有當天日期的新日誌檔案(例如
laravel-YYYY-MM-DD.log)。- 作用: 防止單個日誌檔案無限膨脹,導致磁碟空間耗盡。
- 清理 (Retention): 透過
config/logging.php中daily驅動的days參數來控制。'days' => 14表示系統會自動刪除所有創建日期超過 14 天的舊日誌檔案。- 觀察落差澄清: 即使設定了 14 天,應用程式在任何時間點也只會寫入當天的檔案。舊檔案會保留下來,直到超過設定的
days限制才被清理。
Session
應用程式情境:單一伺服器、低流量,API 為主、Web 為輔。
| 環境變數 | 舊值 (Database) | 建議新值 (File) | 優化理由 |
|---|---|---|---|
SESSION_DRIVER | database | file | database 會造成額外的資料庫 I/O 開銷。單一伺服器上 file 驅動更快,且設置簡單。 |
SESSION_ENCRYPT | false | true | 安全性提升。 對於存儲在本地檔案或資料庫中的 Session 資料進行加密,防止儲存位置洩漏時,Session 數據被直接讀取。 |
SESSION_LIFETIME | 120 | 120 | 2 小時存活時間,Web 應用合理。 |
再討論多一點點
| 驅動 (Driver) | 優點 (Pros) | 缺點 (Cons) | 適用情境 (Recommendation) |
|---|---|---|---|
| file | 簡單、快速、預設。不需要額外的服務。適用於單一伺服器或低流量網站。 | 不適用於多伺服器 (Load Balancer) 架構,因為每個伺服器檔案系統不同。 | 單一伺服器、流量不大,且 Web 部分不重要 的應用。如果您是單機部署,這是一個很好的選擇。 |
| database | 易於設定和管理。多伺服器架構下可共享 Session(但效能不如 Redis/Memcached)。 | 效能開銷較高。每次 Session 讀取/寫入都需要資料庫查詢,可能成為高流量下的瓶頸。 | 快速測試 多伺服器共享 Session 功能,但不推薦用於生產環境。 |
| redis | 極高速度、低延遲。專為快取和 Session 設計。完美支援多伺服器。 | 需要額外設定和維護 Redis 伺服器。 | 高流量、多伺服器 (Load Balancing) 環境,或 Session 讀寫頻繁 的應用程式。這是業界推薦的高效能選擇。 |
執行步驟
- 修改
.env檔案:SESSION_DRIVER=file
SESSION_ENCRYPT=true - 清除設定快取以確保變更生效:
php artisan config:clear
PHP 的 Code Coverage
- 想玩一下程式碼覆蓋率報告
- 先要來設定 Code Coverage 的 Driver: 這裡以 Xdebug 為例
- 安裝 Xdebug (這裡以 Docker 為例)
services:
app:
build:
context: .
dockerfile: Dockerfile
container_name: laravel_app
working_dir: /var/www/html
volumes:
- ./php.ini:/usr/local/etc/php/conf.d/custom.ini
depends_on:
- db
Dockerfile
FROM php:8.4-fpm
# 安裝系統套件與 PHP 擴充
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip \
&& docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
# 安裝 Xdebug
RUN pecl install xdebug \
&& docker-php-ext-enable xdebug
# 安裝 Composer
COPY --from=composer:2.6 /usr/bin/composer /usr/bin/composer
# 設定工作目錄
WORKDIR /var/www/html
# 複製專案檔案
COPY . .
# 權限設定
RUN chown -R www-data:www-data /var/www/html \
&& chmod -R 755 /var/www/html
# 預設啟動命令
CMD ["php-fpm"]
EXPOSE 9000
php.ini : 需要這裡將 xdebug 才能有 程式碼覆蓋
xdebug.mode=coverage
在 phpunit.xml 加入對應的設定
<coverage>
<report>
<html outputDirectory="coverage-html"/>
<clover outputFile="coverage-clover.xml"/>
<text outputFile="php://stdout"/>
</report>
</coverage>
最後在 Docker 裡面跑php artisan test --coverage 之後,你就會看到你的coverage-html這個資料夾和coverage-clover.xml然後到coverage-html資料夾裡用簡單的靜態伺服器打開他即可,你可以使用python3 -m http.server 8080 -d .
切莫追求覆蓋率 100%,而且覆蓋率很高並不表示涵蓋所有的路徑...但有一定品質的覆蓋率是好事。