說明
- 使用的主機提供商是騰訊雲
- 使用部署 L05 電商教程專案作為例子
- 域名自備,除了主域名A解析,再新增一條CNAME泛域名解析
- 主機上已安裝好docker和docker-compose
- 以下操作,docker-compose配置檔案的路徑為
/home/ubuntu/docker
- 進入容器的方式,可以用
docker-compose exec {service_name}
(需在docker-compose.yml所在目錄下操作),也可以在任意目錄執行:docker exec -it {container_name} bash
(nginx
容器的話,bash
換為sh
) - 為了記錄的連貫性,將這個過程中遇到的問題放到文章最後,遇到的時候再去查閱。
docker-compose 環境搭建
docker-compose 環境搭建參考我之前寫的文章:部落格:docker-compose 搭建 dnmp 總結(附踩坑指南)
執行以下命令下載 docker-compose 配置:
git clone https://github.com/HubQin/dnmp.git docker
幾點說明:
- 由於需要用到
npm
安裝和編譯前端資源,所以把它內建到php-fpm
服務所在的容器裡,安裝前注意將dockerfiles/Dockerfile.php73
檔案中Node安裝部分指令註釋去掉 docker-compose.yml
檔案中,mysql部分,資料庫管理員密碼改為自己需要的密碼Redis
配置檔案(/home/ubuntu/docker/conf/redis/redis.conf
)設定註釋掉繫結ip的指令,比如註釋掉:bind 127.0.0.1,另外,需要給redis
設定密碼,在配置檔案中修改:requirepass=xxxxxx(你的redis密碼)php-fpm
容器還內建的supervisor
程式監護工具
以上修改完成,在/home/ubuntu/docker
目錄下執行以下命令啟動各項服務:docker-compose up -d
用到的服務容器明細如下:
- php-fpm 7.3
- mysql 最新版本(當前是8.0.18)
- redis 最新版本(當前是 5.0.7)
- Nginx 最新版本(當前是 1.17.6)
Laravel專案安裝和配置
服務啟動後,會在docker-compose.yml
的上一級建立一個名為project
的資料夾(在本例子中的完整路徑是/home/ubuntu/docker
),將Laravel專案的程式碼放在這裡。
程式碼下載之後,複製一份專案根目錄下的.env.example
檔案,命名為.env
並做如下修改:
APP_NAME=Larashop # <-- 應用名
APP_ENV=production # <-- 執行環境
APP_KEY=base64:oTbcE5B35aiLYtMvxdsaDzplwBYTa5DHX4IfeQ06bws= # <-- 後面將執行命令生成
APP_DEBUG=false # <-- 關閉除錯(部署過程方便除錯可先設為true)
APP_URL=larashop.ishare.cool # <-- 網站地址
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=mysql # <-- mysql主機,注意是填MySQL在docker-compose中的服務名
DB_PORT=3306
DB_DATABASE=laravel-shop # <-- 資料庫名稱
DB_USERNAME=root
DB_PASSWORD=xxxxxx # <-- 資料庫密碼,填寫在docker-compse.yml檔案中設定的密碼
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=redis # <-- 佇列驅動
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=redis # <-- redis主機,填寫規則同mysql
REDIS_PASSWORD=xxxxxx # <-- 填寫在 redis.conf中設定的密碼(requirepass)
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.qq.com
MAIL_PORT=465
MAIL_USERNAME=xxxxxx@qq.com # <-- 你的郵箱
MAIL_PASSWORD=xxxxxx # <--從郵箱服務商獲取的密碼
MAIL_ENCRYPTION=ssl
MAIL_FROM_ADDRESS=xxxxxx@qq.com # <-- 你的郵箱
MAIL_FROM_NAME=Larashop # <-- 應用名
執行docker exec -it docker_mysql_1 bash
進入 mysql 所在容器,登入mysql建立一個資料庫。
執行docker exec -it docker_php-fpm73_1 bash
進入 php 所在的容器(容器名稱可以通過docker ps
命令檢視), 切換到專案程式碼所在目錄(本例子是在var/www/html/larashop
資料夾下),依次做如下操作:
// 安裝依賴
composer install –no-dev –prefer-dist –optimize-autoloader
// 安裝和編譯前端資源
npm install –prod
npm run prod
// 生成key
php artisan key:generate
// 資料表遷移
php artisan migrate –force
// 建立軟連線
php artisan storage:link
// 路由、配置、事件快取
php artisan route:cache
php artisan config:cache
php artisan event:cache
Nginx 配置
在docker/conf/nginx/conf.d
新建一個xxx.conf檔案,這裡暫時先不配置 https,先配置如下:
注意的註釋
server {
listen 80;
server_name larashop.ishare.cool;
# 注意 這裡寫的是nginx容器中的目錄
root /var/www/html/larashop/public;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
try_files $uri /index.php =404;
# 注意這裡需使用 服務名:埠 的形式
fastcgi_pass php-fpm73:9000;
fastcgi_index index.php;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
#fixes timeouts
fastcgi_read_timeout 600;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
配置完成之後,執行docker exec -it docker_nginx_1 sh
進入Nginx容器,執行nginx -s reload
過載配置。
至此,站點就應該可以訪問了。
配置 Supervisor 程式監護
由於程式中使用了 laravel 中的任務佇列、訊息佇列,需要一個程式監護工具來守護佇列監聽程式,這裡使用 supervisor
。
關於Supervisor
的使用,可以參考我之前寫的這篇:部落格:Supervisor 使用總結
在本例中,supervisor
配置如下:
[program:queue]
process_name=%(program_name)s_%(process_num)02d
directory=/var/www/html/larashop
command=php artisan queue:work --tries=3 --sleep=3 --daemon
autostart=true
autorestart=true
numprocs=1
user=root
stopasgroup=true
killasgroup=true
redirect_stderr=true
stdout_logfile=/var/www/html/larashop/storage/logs/queue.log
配置檔案位於:
docker/conf/supervisor/supervisord.conf
配置完成後記得重啟 supervisor
。根據以上配置,有任務被佇列消費,會將日誌寫到storage/logs/queue.log
,效果如下所示:
配置HTTPS
證照生成
這裡使用Let's Encrypt
,生成工具選用acme.sh
。關於acme.sh
的使用,通讀它的wiki文件,基本就可以瞭解如何使用了。
既然我們使用了docker
部署,能用docker
的就都用上docker
,acme.sh
也不例外,所以我們將使用acme.sh
的docker
映象neilpang/acme.sh
來生成證照。執行如下命令就夠了:
docker run --rm -it \
-v "/home/ubuntu/docker/ssl":/acme.sh \
-e DP_Id="141466" \
-e DP_Key="a94e5fb991ce9563acabb84513082ca4" \
neilpang/acme.sh --issue --log --dns dns_dp -d ishare.cool -d *.ishare.cool
以上命令說明:
由於我使用的是騰訊雲的域名,DP_Id 和 DP_Key 可以到DNSPod上建立並獲取
-v "/home/ubuntu/docker/ssl":/acme.sh
將主機上的docker/ssl目錄掛在到容器的/acme.sh目錄,這樣證照生成之後,就會出現在docker/ssl目錄這裡想要配置了泛域名,所以使用
-d ishare.cool -d *.ishare.cool
生成的結果如下:acme.sh
的 wiki 文件說證照60天自動更新,是否能自動更新,只好等60天在驗證了 :cry
修改 Nginx 主配置檔案
/home/ubuntu/docker/conf/nginx/nginx.conf
做如下修改:
user nginx;
worker_processes 2; # 根據主機CPU核心數類配置(lscpu檢視)
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024; # 主機上執行 ulimit -n 檢視
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 60;
types_hash_max_size 2048;
client_body_buffer_size 10K;
client_header_buffer_size 1k;
client_max_body_size 8m;
large_client_header_buffers 2 1k;
client_body_timeout 12;
client_header_timeout 12;
send_timeout 10;
gzip on;
gzip_comp_level 2;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain application/x-javascript text/xml text/css application/xml;
include /etc/nginx/conf.d/*.conf;
}
Nginx安全增強以及SSL配置
- 執行以下命令生成DH檔案:
openssl dhparam -out /home/ubuntu/docker/ssl/dhparam.pem 2048
- 新建ssl檔案(
/home/ubuntu/docker/ssl/options-ssl-nginx.conf
)並新增以下內容:
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 60m;
ssl_session_tickets on;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.4.4 8.8.8.8 valid=300s;
resolver_timeout 10s;
ssl_prefer_server_ciphers on;
ssl_certificate /etc/nginx/ssl/ishare.cool/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/ishare.cool/ishare.cool.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
add_header Strict-Transport-Security "max-age=16070400;includeSubDomains;preload";
add_header X-Frame-Options deny;
add_header X-Content-Type-Options nosniff;
add_header x-xss-protection "1; mode=block";
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: https:; connect-src 'self' https:; img-src 'self' data: https: blob:; style-src 'unsafe-inline' https:; font-src data: https:";
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
該配置將通過include指令包含到虛擬主機檔案中。
修改虛擬主機檔案
/home/ubuntu/docker/conf/nginx/conf.d/larashop.ishare.cool
修改為以下內容:
# 重定向所有http請求
server {
listen 80;
server_name larashop.ishare.cool;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name larashop.ishare.cool;
# 載入ssl配置檔案
include /etc/nginx/ssl/options-ssl-nginx.conf;
# 注意 這裡寫的是nginx容器中的目錄
root /var/www/html/larashop/public;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
location ~ \.php$ {
try_files $uri /index.php =404;
# 注意這裡使用php-fpm服務名
fastcgi_pass php-fpm73:9000;
fastcgi_index index.php;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
#fixes timeouts
fastcgi_read_timeout 600;
include fastcgi_params;
}
location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
expires 365d;
}
location ~ /\.ht {
deny all;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
修改完成後,重啟nginx容器——在/home/ubuntu/docker
目錄執行:docker-compose restart nginx
即可使前面所作的修改生效。
到這裡,HTTPS就配置好了。關於證照生成和nginx的配置,可以參考以下文章:
- docker nginx 利用阿里 key secret 配置泛域名證照
- How To Optimize Nginx Configuration
- 本部落格 Nginx 配置之效能篇
- Nginx 配置 HTTPS 伺服器
- Let’s Encrypt 泛域名證照申請及配置
可能會遇到的問題
/var/www/html/larashop/storage/logs/laravel.log” could not be opened: failed to open stream: Permission denied
解決:
https://stackoverflow.com/questions/234115...sudo chown -R $USER:www-data storage sudo chown -R $USER:www-data bootstrap/cache // 這兩行可選 chmod -R 775 storage chmod -R 775 bootstrap/cache
yansongda/pay v2.9.0 requires ext-bcmath * -> the requested PHP extension bcmath is missing from your system
解決:缺少bcmatch擴充套件,進入php容器,執行:docker-php-ext-install bcmath
安裝。laravel連線redis提示:Connection Refuse
解決:redis.conf 配置檔案中去掉ip地址繫結,同時設定密碼(requirepass欄位)Refused to load the font ‘data:application/font-woff2…’ because it violates the following Content Security Policy directive: “font-src https:”.
解決:修改/home/ubuntu/docker/ssl/options-ssl-nginx.conf
檔案中的Content-Security-Policy
配置,font-src
後面加上data:
以支援base64編碼圖片的顯示。
專案地址
最後曬一下成果:https://larashop.ishare.cool/products
本作品採用《CC 協議》,轉載必須註明作者和本文連結