跳至主要内容

架站筆記

· 閱讀時間約 7 分鐘
提示

持續更新中 💪

我自己寫了一個 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.phpdaily 驅動的 days 參數來控制。
    • 'days' => 14 表示系統會自動刪除所有創建日期超過 14 天的舊日誌檔案。
    • 觀察落差澄清: 即使設定了 14 天,應用程式在任何時間點也只會寫入當天的檔案。舊檔案會保留下來,直到超過設定的 days 限制才被清理。

Session

應用程式情境:單一伺服器、低流量,API 為主、Web 為輔。

環境變數舊值 (Database)建議新值 (File)優化理由
SESSION_DRIVERdatabasefiledatabase 會造成額外的資料庫 I/O 開銷。單一伺服器上 file 驅動更快,且設置簡單。
SESSION_ENCRYPTfalsetrue安全性提升。 對於存儲在本地檔案或資料庫中的 Session 資料進行加密,防止儲存位置洩漏時,Session 數據被直接讀取。
SESSION_LIFETIME1201202 小時存活時間,Web 應用合理。

再討論多一點點

驅動 (Driver)優點 (Pros)缺點 (Cons)適用情境 (Recommendation)
file簡單、快速、預設。不需要額外的服務。適用於單一伺服器或低流量網站。不適用於多伺服器 (Load Balancer) 架構,因為每個伺服器檔案系統不同。單一伺服器、流量不大,且 Web 部分不重要 的應用。如果您是單機部署,這是一個很好的選擇。
database易於設定和管理。多伺服器架構下可共享 Session(但效能不如 Redis/Memcached)。效能開銷較高。每次 Session 讀取/寫入都需要資料庫查詢,可能成為高流量下的瓶頸。快速測試 多伺服器共享 Session 功能,但不推薦用於生產環境。
redis極高速度、低延遲。專為快取和 Session 設計。完美支援多伺服器。需要額外設定和維護 Redis 伺服器。高流量、多伺服器 (Load Balancing) 環境,或 Session 讀寫頻繁 的應用程式。這是業界推薦的高效能選擇。

執行步驟

  1. 修改 .env 檔案:
    SESSION_DRIVER=file
    SESSION_ENCRYPT=true
  2. 清除設定快取以確保變更生效:
    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%,而且覆蓋率很高並不表示涵蓋所有的路徑...但有一定品質的覆蓋率是好事。

Backup