人生就是不斷學習,調整與更新持續前進。

Linux Ubuntu設置技巧 - 反向代理+Rails kamal為輔 V2

這是一篇為你整理的技術部落格文案。這篇文章專為 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 錯誤。

Nginx
 
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)。

YAML
 
# 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 會認為請求不安全。

  • 解法

    1. 檢查 Nginx 是否有 proxy_set_header X-Forwarded-Proto $scheme;

    2. config/environments/production.rb 中加入:

      Ruby
       
      config.hosts << "your-domain.com"
      config.assume_ssl = true # 告訴 Rails 雖然前面是 HTTP 轉發,但請視為 SSL
      

Q2:Nginx 出現 502 Bad Gateway

  • 原因:Nginx 找不到啟動中的 Docker Container。

  • 檢查清單

    • 輸入 docker ps 確認 Kamal 是否真的把 Container 跑起來了。

    • 確認 deploy.ymlhost_port 是否真的是 4000

    • 檢查 Ubuntu 防火牆:sudo ufw allow 4000/tcp(雖然 Nginx 走內網,但有時 Docker 網路會卡住)。

Q3:上傳圖片時出現 413 Request Entity Too Large

  • 原因:Nginx 預設只允許 1MB 的請求。

  • 解法:在 Nginx 的 locationhttp 區塊加入 client_max_body_size 20M;

Q4:靜態檔案(Assets)抓不到?

  • 原因:Rails 在 Production 預設不服務靜態檔案。

  • 解法:在 deploy.yml 的環境變數設定 RAILS_SERVE_STATIC_FILES: true,或者讓 Nginx 直接讀取共享目錄下的 public/ 資料夾(更進階的作法)。


💡 總結小撇步

在 Ubuntu 上修改完 Nginx 設定後,養成好習慣:

  1. 測試語法sudo nginx -t (這能救你一命,避免重啟後 Nginx 整台掛掉)

  2. 重新載入sudo systemctl reload nginx