這是一篇為你整理的技術部落格文案。這篇文章專為 Linux Ubuntu 環境設計,深入探討當你使用 Kamal 部署 Rails 應用程式,並在最前端架設 Nginx 作為反向代理時,該如何配置以及如何避坑。
🚀 Ubuntu 實戰:Nginx + Rails Kamal 完美部署與常見問題排查
在現代的 Rails 部署方案中,Kamal 憑藉著「去中心化、Docker 化」的優勢成為首選。但在 Ubuntu 伺服器上,我們通常不會讓 Kamal 直接面對公網,而是會在最前端架設 Nginx。
為什麼?因為 Nginx 能幫我們處理 SSL 憑證、靜態檔案快取、多個網域名稱分流,以及更強大的流量控制。
🏗️ 系統架構圖
當流量進入伺服器時,路徑如下:
使用者 (Browser) -> Nginx (Host) -> Kamal Proxy / Traefik (Docker) -> Rails App (Container)
1. Nginx 設定範本 (Ubuntu)
請在 /etc/nginx/sites-available/your_app 建立以下設定。這個範本包含了處理 Rails 最重要的 Header 轉發,這能避免常見的 CSRF 錯誤。
upstream rails_app {
# 這裡的 4000 埠號需與你 deploy.yml 中的 boot port 對應
server 127.0.0.1:4000;
}
server {
listen 80;
server_name your-domain.com;
# 強制導向 HTTPS (建議在 Let's Encrypt 設定後開啟)
# return 301 https://$server_name$request_uri;
access_log /var/log/nginx/rails_access.log;
error_log /var/log/nginx/rails_error.log;
location / {
proxy_pass http://rails_app;
# --- 關鍵轉發 Header ---
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; # 讓 Rails 知道這是 HTTPS 或 HTTP
proxy_set_header X-Forwarded-Ssl on;
# 避免上傳大檔案時報錯 413 Request Entity Too Large
client_max_body_size 20M;
# 設定逾時,避免 Kamal 部署瞬間重啟導致的 504
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
}
}
2. Kamal deploy.yml 的配合設定
在 Kamal 中,你必須將 Container 的埠號對應到 Ubuntu Host 的埠號(以上述範例為 4000)。
# config/deploy.yml
service: my-rails-app
image: your-docker-hub-user/my-rails-app
proxy:
host_port: 4000
app_port: 3000 # Rails 預設埠號
# 確保 Rails 接受來自 Nginx 的轉發
env:
clear:
RAILS_SERVE_STATIC_FILES: true
# 這裡非常重要!
RAILS_FORCE_SSL: "true"
3. 常見問題與解決方案 (Pitfalls)
Q1:遇到 Insecure hostname "your-domain.com" 或 CSRF 失敗?
-
原因:Rails 6+ 有
config.hosts保護機制,且如果X-Forwarded-Proto沒有正確傳遞,Rails 會認為請求不安全。 -
解法:
-
檢查 Nginx 是否有
proxy_set_header X-Forwarded-Proto $scheme;。 -
在
config/environments/production.rb中加入:Rubyconfig.hosts << "your-domain.com" config.assume_ssl = true # 告訴 Rails 雖然前面是 HTTP 轉發,但請視為 SSL
-
Q2:Nginx 出現 502 Bad Gateway?
-
原因:Nginx 找不到啟動中的 Docker Container。
-
檢查清單:
-
輸入
docker ps確認 Kamal 是否真的把 Container 跑起來了。 -
確認
deploy.yml的host_port是否真的是4000。 -
檢查 Ubuntu 防火牆:
sudo ufw allow 4000/tcp(雖然 Nginx 走內網,但有時 Docker 網路會卡住)。
-
Q3:上傳圖片時出現 413 Request Entity Too Large?
-
原因:Nginx 預設只允許 1MB 的請求。
-
解法:在 Nginx 的
location或http區塊加入client_max_body_size 20M;。
Q4:靜態檔案(Assets)抓不到?
-
原因:Rails 在 Production 預設不服務靜態檔案。
-
解法:在
deploy.yml的環境變數設定RAILS_SERVE_STATIC_FILES: true,或者讓 Nginx 直接讀取共享目錄下的public/資料夾(更進階的作法)。
💡 總結小撇步
在 Ubuntu 上修改完 Nginx 設定後,養成好習慣:
-
測試語法:
sudo nginx -t(這能救你一命,避免重啟後 Nginx 整台掛掉) -
重新載入:
sudo systemctl reload nginx