本文將分享其在 Windows/docker 中的使用,使用 nssm 部署成服務的方案腳本,區域網中自定義功能變數名稱解決https提示不安全的解決方案,以及一路踩過的坑。 ...
前言
nginx 是一個高性能的開源反向代理伺服器和 web 伺服器,一般用來搭建靜態資源伺服器、負載均衡器、反向代理,本文將分享其在 Windows/docker 中的使用,使用 nssm 部署成服務的方案腳本,區域網中自定義功能變數名稱解決https提示不安全的解決方案,以及一路踩過的坑。
特點
- 高性能:事件驅動的非同步架構,能夠處理大量併發連接
- 靜態資源伺服器:部署前端靜態頁面及靜態資源
- 反向代理伺服器:接收客戶端請求,並將請求轉發到後端服務,可以實現負載均衡、請求分發和緩存等功能
- 支持 HTTPS
使用情況
-
配置功能變數名稱轉發到項目服務
-
外網穿透請求轉發到區域網伺服器
-
測試環境項目的 https 配置
-
需要明白 nginx 預設啟動後會發生什麼?
- 監聽指定埠(預設 80)
- 攔截本機訪問 80 埠的請求到 nginx 來進行處理
- 可以添加配置監聽不同的埠
- 同樣監聽 80,但是可以通過 server_name 來指定不同的功能變數名稱使用不同的規則
- 本地測試可以通過修改 hosts 文件(C:\Windows\System32\drivers\etc\hosts)來將功能變數名稱請求轉發到本機
- 伺服器需要解析功能變數名稱到伺服器 IP,不同的雲商還需要註意其安全組,防火牆是否開啟或需要設置規則
-
Windows 中路徑需要使用 / 或者 \,如路徑
D:\Software\nginx-1.24.0\ssl
nginx.conf 需要配置為D:/Software/nginx-1.24.0/ssl/
或D:\Software\nginx-1.24.0\ssl\
實踐
準備
-
本文版本:v1.24.0
-
使用埠:80 443
-
最基本組成:一個 server 節點一個功能變數名稱配置,要添加其他配置添加 server 節點即可
worker_processes 1; events { worker_connections 1024; } http { server { listen 80; server_name localhost; error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } ```
Windows 安裝使用 nginx
安裝運行
-
直接官網下載即可 v1.24.0
-
下載後解壓到:D:\Software\nginx-1.24.0
-
在目錄輸入框打開 cmd 並運行:
start nginx
運行 nginx,如果埠沒有被占用的話訪問 localhost 即可出現 welcome 頁面
-
嘗試修改配置:D:\Software\nginx-1.24.0\confi\nginx.conf 添加一個文本返回
-
添加的文本及 json 返回
#server{.... #返迴文本 location /text { add_header Content-Type text/plain; return 200 'This is a plain text response.'; } #返回json location /json { add_header Content-Type application/json; return 200 '{"message": "This is a JSON response.233"}'; } #預設配置 location / { root html; index index.html index.htm; } #...} ```
功能變數名稱配置
-
因在本地測試,所以需要使用功能變數名稱訪問到 nginx,需要配置 hosts(伺服器外網功能變數名稱配置就將功能變數名稱解析到伺服器)
-
添加一條記錄:
127.0.0.1 ``nginx.devops.test.com
現在預設就訪問nginx.devops.test.com
的時候就請求到了 nginx 的預設配置了,nginx 預設監聽了 localhost:80 使其返回我們指定的內容 -
添加 server 配置節點,重載配置後訪問,即可看到訪問顯示了配置中的內容
server { listen 80; server_name nginx.devops.test.com; location / { add_header Content-Type text/plain; return 200 'nginx.devops.test.com'; } } ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e62a40257ae548b29b9fab8389027ad5~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=359&h=23&s=1371&e=png&b=0c0c0c) ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d33c2a30c4e14bd68faacd92ac8330d8~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=410&h=122&s=6676&e=png&b=fcfcfc)
-
因為瀏覽器的一些機制,可能會自己預設跳轉到 https,然後還看不到協議,此時就需要手動改下
SSL 證書申請
為了給網站加把鎖(數據傳輸的私密性),一般個人項目用免費的就行,不過有限制,比如通配符、有效期、安全性等,企業一般會使用付費證書,自行購買即可,一般雲商也會提供免費證書,其他免費的目前使用過的就下麵兩種
- 線上網站申請:可以在 freessl 根據需要申請免費/付費證書,其還包含有證書管理和到期提醒等服務
- win-acme:一個免費的開源工具,用於 Windows 上的 Let's Encrypt 證書的自動化獲取和續訂
如果本地也需要使用 https 的話,也可以通過 nginx 來配置證書,為應用加把鎖。伺服器的證書配置使用上面兩種生成,參考下麵配置即可
nginx 本地配置 https
- 使用 openssl 生成自簽證書(會提示不安全,下一步解決)
#依次執行,輸入信息,我這裡都輸入了 ym
openssl genrsa -out server.key 1024
openssl req -new -key server.key -out server.csr
openssl genrsa -out ca.key 1024
openssl req -new -key ca.key -out ca.csr
openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt
openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
- 從圖裡面可以看到都加上 https 了,怎麼還是不安全,甚至第一次還被攔截了,這個是瀏覽器機制問題,找了一晚上,終於找到了解決方案 思路來源 stackoverflow,下麵詳細說明步驟
-
生成 CA 證書(所在目錄:D:/Software/nginx-1.24.0/ssl)
winpty openssl genrsa -des3 -out myCA.key 2048 winpty openssl req -x509 -new -nodes -key myCA.key -sha256 -days 1825 -out myCA.pem ```
-
導入 myCA.pem 證書到受信任的根證書頒發機構(Win+R 打開:
certlm.msc
) -
創建 CA 簽名證書(不同功能變數名稱創建不同的證書)
winpty openssl genrsa -out nginx.devops.test.com.key 2048
winpty openssl req -new -key nginx.devops.test.com.key -out nginx.devops.test.com.csr
-
創建 X509 V3 證書擴展配置文件 nginx.devops.test.com。ext
authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment subjectAltName = @alt_names [alt_names] DNS.1 = nginx.devops.test.com ```
-
生成證書
winpty openssl x509 -req -in nginx.devops.test.com.csr -CA myCA.pem -CAkey myCA.key -CAcreateserial -out nginx.devops.test.com.crt -days 825 -sha256 -extfile nginx.devops.test.com.ext ```
-
配置 nginx
server { listen 80; listen 443 ssl; server_name nginx.devops.test.com; ssl_certificate D:/Software/nginx-1.24.0/ssl/nginx.devops.test.com.crt; ssl_certificate_key D:/Software/nginx-1.24.0/ssl/nginx.devops.test.com.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { add_header Content-Type text/plain; return 200 'nginx.devops.test.com666'; } } ```
-
成功,沒有不安全字樣了
-
如果要在區域網其他機器訪問,也需要執行第 2 步操作導入 myCA.pem 證書,並配置對應的 hosts
使用 nssm 創建 nginx 服務
-
每次改完配置還要敲命令重啟,開機還要啟動,那很明顯是不太方便的,所以部署 nginx 服務就很有必要了
-
和 Windows 計劃任務設置開機啟動相比,我更傾向和習慣於使用 nssm (一個服務封裝程式,它可以方便的將程式封裝成 windows 服務運行)來為應用創建一個服務進行管理。
-
下麵分享兩個快速創建服務的腳本及使用。通過這兩個腳本,只需修改對應路徑,就可以為應用創建服務並做到開機自啟了
-
添加一個啟動 nginx 的腳本 start.bat
- 放在 nginx 目錄中(D:\Software\nginx-1.24.0\start.bat ) ,以管理員 身份運行即可刪除 nginx 進程並重新啟動
- 刪除進程並重啟,測試環境使用,生產環境不建議直接使用
-
@echo off cd /d %~dp0 echo kill nginx taskkill /fi "imagename eq nginx.EXE" /f echo start nginx start nginx echo start nginx success pause
-
將 start.bat 腳本使用 nssm 的方式設置為服務 nssm v2.24 下載
-
下載後解壓:D:\Software\nssm\nssm-2.24\win64
-
在目錄添加 Nginx-service.bat,以快速創建並啟動 nginx 服務,根據需要修改服務名和 nginx 啟動腳本的路徑即可
-
@echo off cd /d %~dp0 nssm stop Nginx-service nssm remove Nginx-service confirm nssm install Nginx-service D:\Software\nginx-1.24.0\start.bat sc start Nginx-service pause
-
-
以管理員 身份運行,即可創建並啟動服務,
-
至此,電腦重啟服務也將自啟,並且還可以通過服務的重新啟動來重啟應用
-
常用命令
-
啟動:
start nginx
-
重載配置:
nginx -s reload
如果出錯會回滾到上一次正確配置文件保持正常運行,可能會存在緩存,Ctrl+F5 刷新瀏覽器 -
停止 nginx(刪除 nginx 進程):
taskkill /fi "imagename eq nginx.EXE" /f
- windows 下使用 nginx 一直有個問題就是重載配置後,不管有沒有問題都可能會啟動多個 nginx 進程,最後重載配置無效,就只能刪除進程後再啟動了
使用 Docker Compose 安裝 nginx
本篇文章基於 Docker V24 及 Docker Compose V2,安裝可以參考之前的文章
配置說明
-
鏡像版本:
nginx:1.24.0
-
指定埠:80 443
-
指定時區:
TZ : 'Asia/Shanghai'
,讓日誌文件顯示北京時間 -
指定掛載目錄
./config/nginx.conf:/etc/nginx/nginx.conf
:預設配置文件,會載入 conf.d 下的所有配置./config/conf.d:/etc/nginx/conf.d
:自定義配置文件./html:/usr/share/nginx/html
:預設的靜態文件目錄./logs:/var/log/nginx
:預設的日誌目錄./ssl:/ssl
:證書目錄,配置中使用 /ssl/xxx 指定
-
配置重載:
docker exec nginx_1_24 nginx -s reload
-
指定網路:devopsnetwork (
docker network create devopsnetwork
) -
目錄結構
配置文件 compose.yml
- 將準備好的 compose.yml config ssl html 拷貝到伺服器
- 然後運行
docker compose up -d
即可
version: '3.1'
services:
nginx:
image: nginx:1.24.0
container_name: nginx_1_24
restart: always
environment:
TZ : 'Asia/Shanghai'
ports:
- "80:80"
- "443:443"
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf
- ./config/conf.d:/etc/nginx/conf.d
- ./html:/usr/share/nginx/html
- ./logs:/var/log/nginx
- ./ssl:/ssl
networks:
- devopsnetwork
networks:
devopsnetwork:
external: true
預設的 nginx.conf v1.24
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
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;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
自定義配置 conf.d/default.conf
將前文 Windows 的配置部分修改到 default.conf 如下所示
server {
listen 80;
listen 443 ssl;
server_name nginx.devops.test.com;
ssl_certificate /ssl/nginx.devops.test.com.crt;
ssl_certificate_key /ssl/nginx.devops.test.com.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
add_header Content-Type text/plain;
return 200 'nginx.devops.test.com 001';
}
}
創建證書 ssl 目錄
上傳生成的 ssl 證書或者在 linux 中使用上面 openssl 的方式重新生成功能變數名稱證書,然後本地添加 pem 證書,即可使用 https
Nginx 的應用
- 前面文章我們安裝了 Apollo,RabbitMQ 及各種常用資料庫,下麵將通過 nginx 給之前文章中的應用配置功能變數名稱轉發
- 通過功能變數名稱訪問到各自應用中,而無需再使用 IP+埠來訪問應用,這樣就算後面部署方式/IP、埠發送變化,只需要修改 nginx 的轉發配置即可
本地使用功能變數名稱前的配置
要想在區域網使用自定義的功能變數名稱訪問應用,需要先配置 hosts 文件,這裡使用 hosts 將功能變數名稱請求指向目標伺服器 192.168.123.214
192.168.123.214 apollo.devops.test.com
192.168.123.214 rabbitmq.devops.test.com
還可以搭建一個 dns 服務,設置本機的 dns,即可將功能變數名稱請求交友 dns 解析到對應服務,並且能夠實現泛解析
Apollo 的轉發配置
-
Apollo 面板地址:http://192.168.123.214:8070/
-
設定功能變數名稱:apollo.devops.test.com
-
對應 server 配置,因為同屬一個網路,所以使用容器名加埠訪問即可
server { listen 80; server_name apollo.devops.test.com; location / { proxy_pass http://apollo_portal_2_1:8070/; #上游主機名 proxy_set_header Host $host; # 客戶端發送的原始主機名 #proxy_set_header host $http_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; } } ```
-
Apollo 配置 https,並重定向 http 到 https
server { listen 80; server_name apollo.devops.test.com; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name apollo.devops.test.com; ssl_certificate /certs/apollo.devops.test.com/server.crt; ssl_certificate_key /certs/apollo.devops.test.com/server.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { proxy_pass http://apollo_portal_2_1:8070/; proxy_set_header host $http_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; } } ```
RabbitMQ 的轉發配置
-
RabbitMQ 面板地址:http://192.168.123.214:15672/#/
-
設定功能變數名稱:rabbitmq.devops.test.com
-
對應 server 配置,因為同屬一個網路,所以使用容器名加埠訪問即可
server { listen 80; server_name rabbitmq.devops.test.com; location / { proxy_pass http://rabbitmq_3_12:15672/; 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; } } ```
-
RabbitMQ 配置 https,並重定向 http 到 https
server { listen 80; server_name rabbitmq.devops.test.com; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name apollo.devops.test.com; ssl_certificate /certs/apollo.devops.test.com/server.crt; ssl_certificate_key /certs/apollo.devops.test.com/server.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { proxy_pass http://apollo_portal_2_1:8070/; proxy_set_header host $http_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; } } ```
相關腳本彙總
-
腳本本地目錄預覽,添加了系統判斷 linux,執行需要給要執行的腳本添加執行許可權:
chmod +x ./01.build-pem.sh
-
nginx-start.bat :刪除 nginx 進程並啟動 nginx 服務
@echo off cd /d %~dp0 echo kill nginx taskkill /fi "imagename eq nginx.EXE" /f echo start nginx start nginx echo start nginx success pause ```
-
nginx-nssm-service.bat 創建 nginx 服務腳本
@echo off cd /d %~dp0 nssm stop Nginx-service nssm remove Nginx-service confirm nssm install Nginx-service D:\Software\nginx-1.24.0\start.bat sc start Nginx-service pause ```
-
01.build-pem.sh 創建自簽證書
#!/bin/sh # 生成根證書,訪問客戶端需要安裝導入 myCA.pem,根據myCA.key,myCA.pem再生成nginx需要的證書 if uname | grep -q "MINGW"; then winpty openssl genrsa -out myCA.key 2048 winpty openssl req -x509 -new -nodes -key myCA.key -days 1825 -out myCA.pem else openssl genrsa -out myCA.key 2048 openssl req -x509 -new -nodes -key myCA.key -days 1825 -out myCA.pem fi ```
-
02.build-ssl.sh 創建功能變數名稱證書
#!/bin/bash if [ "$#" -ne 1 ]; then echo "Usage: Must supply a domain" exit 1 fi DOMAIN=$1 mkdir $DOMAIN #!/bin/sh if uname | grep -q "MINGW"; then winpty openssl genrsa -out $DOMAIN/server.key 2048 winpty openssl req -new -key $DOMAIN/server.key -out $DOMAIN/server.csr else openssl genrsa -out $DOMAIN/server.key 2048 openssl req -new -key $DOMAIN/server.key -out $DOMAIN/server.csr fi cat >$DOMAIN/server.ext <<EOF authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment subjectAltName = @alt_names [alt_names] DNS.1 = $DOMAIN EOF if uname | grep -q "MINGW"; then winpty openssl x509 -req -in $DOMAIN/server.csr -CA ./myCA.pem -CAkey ./myCA.key -CAcreateserial -out $DOMAIN/server.crt -days 36500 -extfile $DOMAIN/server.ext else openssl x509 -req -in $DOMAIN/server.csr -CA ./myCA.pem -CAkey ./myCA.key -CAcreateserial -out $DOMAIN/server.crt -days 36500 -extfile $DOMAIN/server.ext fi ```
-
03.gen.sh 先創建自簽證書,再執行 gen.sh 生成需要的功能變數名稱證書,配置到 nginx 即可
#!/bin/bash # 獲取當前腳本所在目錄 script_dir=$(dirname "$0") sh $script_dir/02.build-ssl.sh nginx.devops.test.com sh $script_dir/02.build-ssl.sh apollo.devops.test.com sh $script_dir/02.build-ssl.sh rabbitmq.devops.test.com ```
踩過的坑
Windows 環境 nginx -s reload 後多個 nginx 進程
目前只能通過taskkill /fi "imagename eq nginx.EXE" /f
刪除進程再啟動
Windows 中使用 openssl 需要添加首碼 winpty openssl
一開始是執行 openssl genrsa -out server.key 2048
命令卡死
後面找到一篇文章說是 git bash 密碼的問題,加了密碼參數確實可以了:openssl genrsa -des3 -out myCA.key -passout pass:mima 2048
但是後續使用 openssl req
還是卡死,
最後解決自簽證書授信的時候才發現是需要加上 winpty 使用才是正解
本地自簽證書配置 https 瀏覽器依舊提示不安全
生產對應功能變數名稱的證書,併在客戶端安裝證書,找到的 解決方案 ,以及思路來源 stackoverflow
容器中 nginx.conf 預設配置問題
不同的版本可能預設配置不一樣,可以先不掛載配置把容器的預設配置文件複製出來,在預設配置基礎上進行修改,可少走彎路。尤其如果是將 Windows 上面 的配置修改到容器中,需要註意路徑問題。
比如 windows 中配置靜態站點根目錄:root html;
,在容器中則需要配置為root /usr/share/nginx/html;
才生效
容器中重載配置
docker exec nginx_1_24 nginx -s reload
相關文檔
後語
一直都是用到了就搜索,此番整理,加深使用,以備後用
最深刻的是本篇對區域網自定義功能變數名稱不安全https提示問題的解決,簡直賞心悅目。
作者:易墨
Github:yimogit
純靜態工具站點:metools
說明:歡迎拍磚,不足之處還望園友們指出;
迷茫大概是因為想的太多做的太少。