GCP自己架設前後端Docker容器筆記和踩過的雷 2025-07-07 15:45:12
前言
架設這個網站dbvs.space已經快3年了
這是一台Laravel架設的網站,沒有前後端分離
隨著新技術的出現
現在比較高階的工程師職位要求的技術也越來越多
所以打算另外架設一個網站
1.在GCP上面架設新的機器,並在Godaddy買新的域名
2.在機器上架設Docker容器,分成前端和後端,並用nginx容器反向代理將子域名導向兩個容器
3.用certbot容器自動建立ssl憑證
4.前端機器用Vuejs,後端機器用Laravel建立RESTful API
5.學習編寫RESTful API和API文件,以及前後端的單元測試和整合測試
以後Blog的文章就移到那邊去,並且新增留言功能讓有緣人留言互相交流
這篇文章先從機器架設開始
架設Docker容器步驟
1.GCP建立一個CentOS機器,並安裝docker和docker compose
注意事項 : 因為要讓nginx docker容器來處理反向代理,所以host機器上不用安裝nginx(因為之前習慣機器建好第一步就安裝nginx,導致我第一次嘗試的時候差點發瘋)
2.在根目錄建立一個專案目錄結構
your-project/
├── docker-compose.yml
├── nginx/
│ └── default.conf
├── certbot/
│ └── conf/
│ └── www/
├── frontend/
│ └── (Vue 專案程式碼)
└── backend/
└── (Laravel 專案程式碼)
3.Docker Compose 配置 (docker-compose.yml
)
services:
nginx:
image: nginx:latest
container_name: nginx_proxy
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
- ./certbot/conf:/etc/nginx/ssl:ro # 掛載 Let's Encrypt 憑證
- ./certbot/www:/var/www/certbot # 掛載用於憑證驗證的目錄
depends_on:
- frontend
- backend
restart: unless-stopped
networks:
- app_network
frontend:
build:
context: ./frontend # Vue 專案的路徑
dockerfile: Dockerfile.frontend
container_name: vue_frontend
restart: unless-stopped
networks:
- app_network
backend:
build:
context: ./backend # Laravel 專案的路徑
dockerfile: Dockerfile.backend
container_name: laravel_backend
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
# 其他 Laravel 環境變數
restart: unless-stopped
networks:
- app_network
redis:
image: redis:latest
container_name: redis_cache
ports:
- "6379:6379" # 僅在需要從外部訪問時才開放,一般情況下不建議
restart: unless-stopped
networks:
- app_network
certbot:
image: certbot/certbot
container_name: certbot_manager
volumes:
- ./certbot/conf:/etc/letsencrypt # 憑證儲存路徑
- ./certbot/www:/var/www/certbot # Webroot 路徑
command: certonly --webroot -w /var/www/certbot --email your_email@example.com -d frontend.domain.com -d backend.domain.com --agree-tos --no-eff-email --force-renewal
# 第一次運行時用於獲取憑證,之後可以註釋掉或修改為 renew 命令
# command: renew --webroot -w /var/www/certbot --post-hook "service nginx reload" # 自動更新並重載 Nginx
depends_on:
- nginx # Certbot 需要 Nginx 運行才能進行 Webroot 驗證
networks:
- app_network
networks:
app_network:
driver: bridge
4.Dockerfile 配置
前端 Dockerfile (frontend/Dockerfile.frontend
)
# Vue 前端 Dockerfile
FROM node:lts-alpine as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
後端 Dockerfile (backend/Dockerfile.backend
)
# Laravel 後端 Dockerfile
FROM php:8.3-fpm-alpine
WORKDIR /var/www/html
# 安裝 PHP 擴展和 Composer
RUN apk add --no-cache \
nginx \
supervisor \
curl \
libpng-dev \
libjpeg-turbo-dev \
libzip-dev \
libpq-dev \
icu-dev \
&& docker-php-ext-install pdo_mysql gd zip bcmath opcache intl \
&& rm -rf /var/cache/apk/*
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
COPY . .
RUN composer install --no-dev --optimize-autoloader
RUN php artisan optimize
# 配置權限
RUN chown -R www-data:www-data /var/www/html/storage \
&& chown -R www-data:www-data /var/www/html/bootstrap/cache \
&& chmod -R 775 /var/www/html/storage \
&& chmod -R 775 /var/www/html/bootstrap/cache
EXPOSE 9000
CMD ["php-fpm"]
5.Nginx 配置 (nginx/default.conf
) 注意事項 : 因為要先讓certbot建立第一次的ssl憑證,所以nginx只要設定80port讓certbot容器可以連進來建立憑證(我第一次架的時候有寫443port的部分,結果nginx的容器一直打不開,docker status 一直 restarting)
server {
listen 80;
listen [::]:80;
server_name api1.domain.com api2.domain.com;
# Certbot 驗證路徑
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}
6.第一次獲取 Let's Encrypt 憑證
先運行 Nginx並確認 nginx docker有正常開啟
docker compose up -d --build nginx
docker ps -a 確認nginx docker有正常開啟後運行certbot docker建立憑證
docker compose up -d --build certbot
執行docker logs certbot_manager查看日誌確定取得憑證成功
docker logs certbot_manager
7.拿完憑證要更改docker compose文件和nginx文件
Nginx 文件 (nginx/default.conf
)
server {
listen 80;
listen [::]:80;
server_name api1.domain.com api2.domain.com;
# Certbot 驗證路徑
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri; # 強制跳轉到 HTTPS
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name api1.domain.com;
ssl_certificate /etc/nginx/ssl/live/api1.domain.com/fullchain.pem; # Certbot 生成的憑證
ssl_certificate_key /etc/nginx/ssl/live/api1.domain.com/privkey.pem; # Certbot 生成的私鑰
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1.2 TLSv1.3;
# Vue 前端反向代理
location / {
proxy_pass http://frontend:80; # frontend 是 Docker Compose 中定義的服務名稱
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;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name api2.domain.com;
ssl_certificate /etc/nginx/ssl/live/api2.domain.com/fullchain.pem; # Certbot 生成的憑證
ssl_certificate_key /etc/nginx/ssl/live/api2.domain.com/privkey.pem; # Certbot 生成的私鑰
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1.2 TLSv1.3;
# 指向 Laravel 專案的 public 目錄作為根目錄
# /var/www/html 是 backend 容器內 Laravel 專案的根目錄,所以 public 會是 /var/www/html/public
root /var/www/html/public; # <--- 關鍵更改
index index.php index.html index.htm; # 定義索引檔案
# 處理所有請求,如果不是真實檔案或目錄,就重寫到 index.php
location / {
try_files $uri $uri/ /index.php?$query_string; # <--- 關鍵更改
}
# 將 PHP 請求轉發到 PHP-FPM 服務 (backend 容器)
location ~ \.php$ {
# 注意:這裡使用 fastcgi_pass 而不是 proxy_pass
fastcgi_pass backend:9000; # <--- 關鍵更改
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# 這些是在 Nginx 容器內設置的頭部,用於轉發給 PHP-FPM
fastcgi_param Host $host;
fastcgi_param HTTPS on; # 告知 Laravel 請求是 HTTPS
fastcgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;
fastcgi_param HTTP_X_REAL_IP $remote_addr;
fastcgi_param HTTP_X_FORWARDED_PROTO $scheme;
}
# 阻止訪問敏感檔案和目錄
location ~ /\.env {
deny all;
}
location ~ /\.git {
deny all;
}
}
Docker Compose 文件 (docker-compose.yml
)
certbot 的 command更改
certbot:
image: certbot/certbot
container_name: certbot_manager
volumes:
- ./certbot/conf:/etc/letsencrypt # 憑證儲存路徑
- ./certbot/www:/var/www/certbot # Webroot 路徑
# 第一次運行時用於獲取憑證,之後可以註釋掉或修改為 renew 命令
command: renew --webroot -w /var/www/certbot --post-hook "service nginx reload" # 自動更新並重載 Nginx
depends_on:
- nginx # Certbot 需要 Nginx 運行才能進行 Webroot 驗證
networks:
- app_network
8.改完文件重新啟動nginx
docker compose restart nginx
9.啟動所有的服務
docker compose up -d --build
10.確認機器正常運作後子域名應該就可以正常顯示了
docker ps -a