前言 在雲端部署 Spring Boot API 時,設定 HTTPS 是必要的安全措施,特別是當你的前端應用需要調用 API 時。本文將完整介紹如何在 GCP VM 上部署 Spring Boot 應用,並使用 Nginx 反向代理搭配 Let’s Encrypt 實現自動化的 HTTPS 配置。
架構概述 我們將建立以下架構:
1 用戶 → 域名(HTTPS:443 ) → Nginx → Spring Boot (8080 ) → MySQL
優勢:
✅ 免費的 SSL 證書(Let’s Encrypt)
✅ 自動證書更新
✅ 反向代理提供額外安全性
✅ 支援 CORS 跨域請求
步驟一:購買並設定域名 1.1 購買域名 推薦在 Namecheap 購買域名:
.com 域名:約 $12/年
.xyz 域名:約 $3/年(經濟選擇)
1.2 設定 DNS A Record 在 Namecheap 控制台設定:
路徑 :Domain List → Manage → Advanced DNS
設定內容 :
1 2 3 4 Type: A RecordHost: apiValue: YOUR_GCP_VM_EXTERNAL_IP # 替換為你的 GCP VM 外部 IP TTL: Automatic
1.3 驗證 DNS 生效 1 nslookup api.yourdomain.com
預期輸出 :
1 2 3 4 5 6 Server: 8.8 .8.8 Address: 8.8 .8.8 Non-authoritative answer: Name: api.yourdomain.comAddress: YOUR_GCP_VM_EXTERNAL_IP
步驟二:安裝必要軟體 2.1 更新系統並安裝 Nginx 1 2 sudo apt update && sudo apt upgrade -ysudo apt install nginx -y
驗證安裝 :
1 sudo systemctl status nginx
預期輸出 :
1 2 3 4 5 6 7 ● nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2025-09-12 07:15:23 UTC; 1min 23s ago Docs: man:nginx(8) Main PID: 1234 (nginx) Tasks: 3 (limit: 1152 ) Memory: 6. 1M
2.2 安裝 Certbot 1 2 3 4 sudo apt install snapd -ysudo snap install core; sudo snap refresh coresudo snap install --classic certbotsudo ln -s /snap/bin/certbot /usr/bin/certbot
驗證安裝 :
預期輸出 :
2.3 安裝 Java(如果未安裝) 1 2 sudo apt install openjdk-17-jre -y java --version
步驟三:設定 Nginx 反向代理 3.1 建立 Nginx 配置檔 1 sudo nano /etc/nginx/sites-available/default
完整配置內容 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 server { listen 80 ; server_name api.yourdomain.com; location / { proxy_pass http://127.0.0.1:8080; 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 ; add_header Access-Control-Allow-Origin * always; add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE" always; add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always; if ($request_method = 'OPTIONS' ) { add_header Access-Control-Allow-Origin * always; add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE" always; add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always; add_header Access-Control-Max-Age 1728000 always; add_header Content-Type 'text/plain; charset=utf-8' always; add_header Content-Length 0 always; return 204 ; } } }
3.2 測試並重載 Nginx 設定
預期輸出 :
1 2 nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
1 2 sudo systemctl reload nginxsudo systemctl enable nginx
3.3 設定防火牆 1 2 3 sudo ufw allow 'Nginx Full' sudo ufw allow sshsudo ufw enable
檢查防火牆狀態 :
預期輸出 :
1 2 3 4 5 6 Status: activeTo Action From Nginx Full ALLOW Anywhere22 /tcp ALLOW Anywhere
步驟四:部署 Spring Boot 應用 4.1 上傳 JAR 檔案 從本機執行 :
1 scp your-app.jar username@YOUR_GCP_VM_EXTERNAL_IP:~/
4.2 SSH 連線到 GCP VM 1 ssh username@YOUR_GCP_VM_EXTERNAL_IP
4.3 啟動 Spring Boot 應用 1 2 3 4 5 nohup java -jar your-app.jar > app.log 2>&1 &echo $! > app.pid
4.4 驗證應用運行 1 2 netstat -tlnp | grep :8080
預期輸出 :
1 tcp6 0 0 :::8080 :::* LISTEN 12345 /java
1 2 curl -I http://localhost:8080
預期輸出 :
1 2 3 4 HTTP /1 .1 200 Content -Type: application/jsonContent -Length: 45 Date : Thu, 12 Sep 2025 07 :30 :15 GMT
4.5 測試通過 Nginx 訪問 1 curl -I http://api.yourdomain.com
步驟五:申請 SSL 證書 5.1 使用 Certbot 申請證書 重要 :確保域名 DNS 已生效且 HTTP 可正常訪問。
1 sudo certbot --nginx -d api.yourdomain.com
執行過程輸出 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Saving debug log to /var/log /letsencrypt/letsencrypt.log Requesting a certificate for api.yourdomain.com Successfully received certificate. Certificate is saved at: /etc/letsencrypt/live/api.yourdomain.com /fullchain.pem Key is saved at: /etc/letsencrypt/live/api.yourdomain.com /privkey.pem This certificate expires on 2025 -12 -11 . These files will be updated when the certificate renews. Certbot has set up a scheduled task to automatically renew this certificate in the background. Deploying certificate Successfully deployed certificate for api.yourdomain.com to /etc/nginx/sites-enabled/default Congratulations! You have successfully enabled HTTPS on https://api.yourdomain.com
5.2 驗證 SSL 設定 1 curl -I https://api.yourdomain.com
預期輸出 :
1 2 3 4 5 6 7 HTTP/2 200 server : nginx/1.18.0date : Thu, 12 Sep 2025 07:35:20 GMTcontent-type : application/jsoncontent-length : 45access-control-allow-origin : *access-control-allow-methods : GET, POST, OPTIONS, PUT, DELETE
5.3 檢查自動生成的 Nginx 配置 1 sudo cat /etc/nginx/sites-enabled/default
你會看到 Certbot 自動添加了 SSL 相關配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 server { server_name api.yourdomain.com; location / { } listen 443 ssl; ssl_certificate /etc/letsencrypt/live/api.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/api.yourdomain.com/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; }server { if ($host = api.yourdomain.com) { return 301 https://$host $request_uri ; } listen 80 ; server_name api.yourdomain.com; return 404 ; }
步驟六:設定自動更新 6.1 驗證自動更新服務 1 sudo systemctl status certbot.timer
預期輸出 :
1 2 3 4 5 ● certbot.timer - Run certbot twice daily Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; vendor preset: enabled) Active: active (waiting) since Thu 2025-09-12 07:35:45 UTC; 2min ago Docs: man:systemd.timer(5) Trigger: Thu 2025-09-12 17:42:15 UTC; 10h left
6.2 查看定時任務 1 sudo systemctl list-timers | grep certbot
6.3 測試自動更新機制 1 sudo certbot renew --dry-run
預期輸出 :
1 2 3 4 5 6 7 8 9 10 11 12 Saving debug log to /var/log /letsencrypt/letsencrypt.log - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Processing /etc/letsencrypt/renewal/api.yourdomain.com .conf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Account registered. Simulating renewal of an existing certificate for api.yourdomain.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Congratulations, all simulated renewals succeeded: /etc/letsencrypt/live/api.yourdomain.com /fullchain.pem (success) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
步驟七:效能與記憶體優化 7.1 優化 Nginx 設定 1 sudo nano /etc/nginx/nginx.conf
在相應區塊中修改或添加 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 user www-data;worker_processes 1 ;pid /run/nginx.pid;events { worker_connections 512 ; use epoll ; multi_accept on ; }http { sendfile on ; tcp_nopush on ; tcp_nodelay on ; keepalive_timeout 15 ; types_hash_max_size 2048 ; server_tokens off ; gzip on ; gzip_vary on ; gzip_min_length 1024 ; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/atom+xml; include /etc/nginx/mime.types; include /etc/nginx/conf.d/*.conf ; include /etc/nginx/sites-enabled/*; }
1 2 sudo nginx -tsudo systemctl reload nginx
7.2 優化 JVM 記憶體設定 建立啟動腳本:
腳本內容 :
1 2 3 4 5 #!/bin/bash export JAVA_OPTS="-Xms128m -Xmx512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200" nohup java $JAVA_OPTS -jar your-app.jar > app.log 2>&1 &echo $! > app.pidecho "Application started with PID: $(cat app.pid) "
7.3 建立停止腳本
腳本內容 :
1 2 3 4 5 6 7 8 9 10 #!/bin/bash if [ -f app.pid ]; then PID=$(cat app.pid) echo "Stopping application with PID: $PID " kill $PID rm app.pid echo "Application stopped" else echo "No PID file found" fi
7.4 記憶體使用監控
預期輸出 :
1 2 3 total used free shared buff/cache availableMem : 985 Mi 650 Mi 120 Mi 12 Mi 215 Mi 180 MiSwap : 0 B 0 B 0 B
步驟八:建立系統服務(可選) 8.1 建立 systemd 服務檔 1 sudo nano /etc/systemd/system/spring-boot-api.service
服務檔內容 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [Unit] Description =Spring Boot APIAfter =network.target[Service] Type =simpleUser =your-usernameWorkingDirectory =/home/your-usernameExecStart =/usr/bin/java -Xms128m -Xmx512m -XX:+UseG1GC -jar /home/your-username/your-app.jarRestart =alwaysRestartSec =10 StandardOutput =journalStandardError =journal[Install] WantedBy =multi-user.target
8.2 啟用服務 1 2 3 sudo systemctl daemon-reloadsudo systemctl enable spring-boot-apisudo systemctl start spring-boot-api
8.3 檢查服務狀態 1 sudo systemctl status spring-boot-api
完成驗證 9.1 完整功能測試 1 2 3 4 5 6 7 8 9 10 11 12 curl -I http://api.yourdomain.com curl https://api.yourdomain.com/api/health curl -X OPTIONS https://api.yourdomain.com/api/test \ -H "Origin: https://example.com" \ -H "Access-Control-Request-Method: POST" \ -H "Access-Control-Request-Headers: Content-Type" \ -v
9.3 SSL 證書驗證 在瀏覽器中訪問 https://api.yourdomain.com
,確認:
✅ 綠色鎖頭圖示
✅ 證書有效期顯示正確
✅ 沒有安全警告
故障排除 DNS 相關問題 DNS 未生效 :
1 2 3 4 5 6 dig api.yourdomain.com nslookup api.yourdomain.com 8.8.8.8
SSL 證書問題 SSL 申請失敗 :
1 2 3 4 5 6 7 8 sudo netstat -tlnp | grep :80 curl -I http://api.yourdomain.comsudo tail -f /var/log/letsencrypt/letsencrypt.log
證書更新失敗 :
1 2 3 4 5 sudo certbot renewsudo certbot certificates
應用程式問題 Spring Boot 應用無法啟動 :
1 2 3 4 5 6 7 8 tail -f app.logsudo netstat -tlnp | grep :8080 java --version
記憶體不足 :
1 2 3 4 5 6 7 8 9 10 free -h ps aux --sort =-%mem | head sudo fallocate -l 1G /swapfilesudo chmod 600 /swapfilesudo mkswap /swapfilesudo swapon /swapfileecho '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
網路連線問題 CORS 錯誤 :
1 2 3 4 5 6 7 8 sudo nginx -t grep -n "Access-Control" /etc/nginx/sites-enabled/default curl -X OPTIONS https://api.yourdomain.com/api/test \ -H "Origin: https://yourfrontend.com" \ -v
502 Bad Gateway :
1 2 3 4 5 6 ps aux | grep java netstat -tlnp | grep :8080sudo tail -f /var/log/nginx/error.log
安全性加強建議 10.1 更新 SSL 安全設定 1 sudo nano /etc/letsencrypt/options-ssl-nginx.conf
確保包含以下安全標頭:
1 2 3 4 5 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;add_header X-Frame-Options DENY always;add_header X-Content-Type-Options nosniff always;add_header X-XSS-Protection "1; mode=block" always;add_header Referrer-Policy "strict-origin-when-cross-origin" always;
10.2 限制訪問頻率 在 Nginx 中添加速率限制:
1 2 3 4 5 6 7 8 9 10 http { limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; server { location /api/ { limit_req zone=api burst=20 nodelay; } } }
維護檢查清單 定期維護任務 每月檢查 :
每季檢查 :
監控命令 :
1 2 3 4 5 6 7 8 9 10 11 12 13 echo "=== 系統狀態 ===" date echo "=== 記憶體使用 ===" free -hecho "=== 磁碟使用 ===" df -hecho "=== 服務狀態 ===" sudo systemctl status nginx spring-boot-apiecho "=== SSL 證書狀態 ===" sudo certbot certificatesecho "=== 網路連線測試 ===" curl -I https://api.yourdomain.com
總結 透過以上步驟,我們成功建立了一個完整的 HTTPS API 部署方案:
技術架構 :
前端 :Vue PWA (Cloudflare Pages)
後端 :Spring Boot API (GCP VM)
代理 :Nginx 反向代理
SSL :Let’s Encrypt 自動化證書
域名 :自定義域名解析
關鍵優勢 :
✅ 安全性 :Let’s Encrypt SSL 證書提供 HTTPS 加密
✅ 自動化 :證書每 90 天自動更新
✅ 效能 :Nginx 反向代理提供快取和壓縮
✅ 跨域支援 :完整的 CORS 設定
✅ 成本效益 :域名費用 $3-12/年,其他完全免費
✅ 可擴展性 :可輕鬆添加負載平衡和多實例
適用場景 :
個人專案和中小型應用
MVP 產品快速上線
學習和實驗專案
成本敏感的商業應用
這個架構提供了生產級別的安全性和可靠性,同時保持了簡單的維護成本和良好的效能表現。
注意事項 :
請將所有 yourdomain.com
替換為你的實際域名
將 YOUR_GCP_VM_EXTERNAL_IP
替換為你的 GCP VM 外部 IP
將 your-app.jar
替換為你的實際應用程式檔名
根據你的應用需求調整 JVM 記憶體設定