Nginx簡單介紹
Nginx 是一個高性能的HTTP和反向代理web伺服器,同時也提供了IMAP/POP3/SMTP服務,因它的穩定性、豐富的功能集、簡單的配置檔案和低系統資源的消耗而聞名。在BSD-like 協定下發行。其特點是占有記憶體少,并發能力強,事實上nginx的并發能力在同類型的網頁伺服器中表現較好,中國大陸使用nginx網站使用者有:百度、京東、新浪、網易、騰訊、淘寶等。
優點
- 在性能上,Nginx 是一個很強大的高性能Web和反向代理服務,采用C進行編寫,在連接配接高并發的情況下,能夠支援高達 5萬個并發連接配接數的響應,并且cpu、記憶體等資源消耗卻非常低,運作非常穩定。
- Nginx選擇了 epoll and kqueue作為IO模型。Nginx以事件驅動的方式編寫,是以有非常好的性能。
- 在功能上,Nginx是優秀的代理伺服器和負載均衡伺服器;
- 在安裝配置上,Nginx安裝簡單、配置靈活。
- Nginx支援熱部署,啟動速度特别快,還可以在不間斷服務的情況下對軟體版本或配置進行更新,即使運作數月也無需重新啟動。
在微服務的體系之下,Nginx正在被越來越多的項目采用作為網關來使用,配合Lua做限流、熔斷等控制。
下圖為Nginx的反向代理結構圖
(圖檔來自于https://www.nginx.cn/nginxchswhyuseit)
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5SM1kTOyEmY4MDNzQTY0ImNzYzX3QTNzQTM5AzLcFTMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
對于大多數使用者來說,Nginx隻是一個靜态檔案伺服器或者http請求轉發器,它可以把靜态檔案的請求直接傳回靜态檔案資源,把動态檔案的請求轉發給背景的處理程式。
應用場景
- http伺服器。Nginx是一個http服務可以獨立提供http服務。可以做網頁靜态伺服器。
- 虛拟主機。可以實作在一台伺服器虛拟出多個網站。
- 反向代理,負載均衡。當網站的通路量達到一定程度後,單台伺服器不能滿足使用者的請求時,需要用多台伺服器叢集可以使用nginx做反向代理。并且多台伺服器可以平均分擔負載,不會因為某台伺服器負載高當機而某台伺服器閑置的情況。
Docker 安裝部署Nginx
查找 nginx image 鏡像
docker search nginx
在鏡像倉庫裡面,有如下鏡像。
拉取nginx鏡像
這裡我們拉取官方的最新版本的鏡像:
docker pull nginx:latest
檢視本地鏡像
docker images
檢視nginx檔案大緻結構
我們先啟動一個簡單的nginx容器,好進去看看他的配置檔案結構是怎樣的,然後将這些檔案挂載出來
啟動nginx
啟動一個簡單的nginx
docker run -itd --name nginx nginx
進入docker的nginx容器
docker exec -it nginx /bin/bash
确定進入容器内部後,用下面兩個指令查找nginx的配置檔案在哪:
# 查找nginx配置檔案default.conf
# 這個在/etc/nginx/conf.d/default.conf
find / -name "default.conf"
# 查找nginx配置檔案nginx.conf
# 這個在/etc/nginx/nginx.conf
find / -name "nginx.conf"
# 注:兩者不在同一目錄下。
進入到/etc/nginx 的檔案夾下面
列印配置檔案内容到螢幕上
cat nginx.conf
conf.d是一個檔案夾,裡面存放着default.conf
cd到conf.d的檔案夾下面,然後列印檔案内容到螢幕上面
cat default.conf
我們可以從中知道nginx的配置的一些資訊(比如日志檔案夾的位置)
退出容器
exit
建立本地檔案夾
以便于容器挂載,我在主控端的/usr/local檔案夾下面部署
mkdir -p /usr/local/nginx/html
mkdir -p /usr/local/nginx/config
mkdir -p /usr/local/nginx/config/conf.d
mkdir -p /usr/local/nginx/logs
mkdir -p /usr/local/nginx/ssl
遞歸賦予這個檔案夾的讀寫執行權限
chmod -R 777 /usr/local/nginx
使用docker的cp指令把這兩個配置檔案複制到剛剛建好的目錄下(容器需要成功建構成功才能cp出來,容器關閉了也可以cp出來):
把docker内的default.conf複制到外部
docker cp nginx:/etc/nginx/conf.d/default.conf /usr/local/nginx/config/conf.d/default.conf
把docker内的nginx.conf複制到外部
docker cp nginx:/etc/nginx/nginx.conf /usr/local/nginx/config/nginx.conf
将html檔案也移動到外面
注意:docker 挂載檔案夾的時候,如果本來鏡像裡面就有這些檔案,必須移動到主控端的挂載檔案夾下面(根據我的實驗好像不會自動拷貝到主控端上面),而如果是docker 啟動運作生成的檔案可以不用放到主控端外面,這裡的html檔案應該是壓縮在nginx鏡像裡面的,是以這裡必須要移動到外面
docker cp nginx:/usr/share/nginx/html/50x.html /usr/local/nginx/html/50x.html
docker cp nginx:/usr/share/nginx/html/index.html /usr/local/nginx/html/index.html
nginx.conf配置檔案 (配置nginx的一些資訊)
#運作nginx的使用者
user nginx;
#啟動程序設定成和CPU數量相等
worker_processes 1;
#全局錯誤日志及PID檔案的位置
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
#工作模式及連接配接數上限
events {
#單個背景work程序最大并發數設定為1024
worker_connections 1024;
}
http {
#設定mime類型
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壓縮
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
可以看到最後一行還要包含另一個配置檔案conf.d/default.conf,用來配置server字段
default.conf(這裡主要配置server)
server {
listen 80; #偵聽80端口,如果強制所有的通路都必須是HTTPs的,這行需要登出掉
listen [::]:80;
server_name localhost; #域名
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
# 定義首頁索引目錄和名稱,nginx的預設首頁的html檔案,這個html可以自己定義一個,任意的都可以。
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#定義錯誤提示頁面
#error_page 404 /404.html;
#重定向錯誤頁面到 /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
這個時候直接通過IP位址就可以通路nginx定義的這個html檔案了。但是這個時候的通路隻是http的,https的通路還是不行的,需要添加證書到nginx伺服器。
停止先前建立運作的容器nginx
docker stop nginx
删除容器nginx
docker rm nginx
運作挂載到主控端的容器
帶着挂載檔案的指令啟動nginx:(必須删除前面的,因為不僅名稱沖突,端口号也沖突,不過你可以建立名稱不同,監聽端口不同的多個nginx伺服器)
docker run -itd \
--name nginx \
-p 442:443\
-p 8080:80 \
-v /usr/local/nginx/html:/usr/share/nginx/html \
-v /usr/local/nginx/config/nginx.conf:/etc/nginx/nginx.conf \
-v /usr/local/nginx/config/conf.d/default.conf:/etc/nginx/conf.d/default.conf \
-v /usr/local/nginx/logs:/var/log/nginx \
-v /usr/local/nginx/ssl:/ssl \
nginx
參數說明:
–name nginx:容器名稱。
-p 80:80: 端口進行映射,将本地 8080 端口映射到容器内部的 80 端口。
-itd 是docker run 的參數,等價于 -i -t -d 的結合,具體說明可以docker run --help 檢視
-v表示挂載的檔案,-v [該檔案在容器外部的位置]:[該檔案在容器内部的位置]
檢視正在運作的容器
docker ps -a
查詢nginx端口8080是否開放(主控端)
firwall-cmd:是Linux提供的操作firewall的一個工具
firewall-cmd --query-port=8080/tcp
答案是no
對外開放這個端口
firewall-cmd --permanent --add-port=8080/tcp
重新開機防火牆(修改配置後要重新開機防火牆)
firewall-cmd --reload
再次查詢已經變為yes
但是還是無法通路,還需要去伺服器的控制台去開啟防火牆,
如果是阿裡雲,還需要在安全組裡面手動添加端口 ,配置可由那些IP通路。不然你防火牆開放了端口也是沒用的(親身經曆)。
伺服器控制台設定好了以後,就可以通路了
這裡的通路是不安全的,可以通過添加SSL證書來使用HTTPS來通路。
查詢nginx端口442是否開放(主控端)
主控端的442端口映射到了nginx容器的443端口
firwall-cmd:是Linux提供的操作firewall的一個工具
firewall-cmd --query-port=442/tcp
對外開放這個端口
如果上一條指令的答案是no,那麼久對外開放這個442端口
firewall-cmd --permanent --add-port=442/tcp
重新開機防火牆(修改配置後要重新開機防火牆)
firewall-cmd --reload
同樣的去伺服器的控制台去開啟防火牆,如果是阿裡雲,還需要在安全組裡面手動添加端口 ,配置可由那些IP通路。
openssl添加SSL,使之可以安全通路(不推薦)
openssl生成的證書浏覽器不認,還要一系列步驟很麻煩
我這裡謹做個記錄(大家可以跳轉到給購買域名添加SSL部分)
或者嘗試Let’s Encrypt來添加SSL
openssl生成證書的大緻流程
(圖檔來自于javascript:void(0))
我們這裡隻生成server證書
生成服務端私鑰(server.key),這裡需要設定兩遍密碼:
openssl genrsa -des3 -out server.key 2048
生成服務端證書簽名請求(server.csr)
openssl req -new -key server.key -out server.csr
參數設定,首先這裡需要輸入之前設定的密碼,
然後需要輸入如下的資訊,大概填一下就可以了,反正是測試用的
nginx啟動的時候需要輸入server.key的密碼,解決辦法是可以使用原key來生成解密後的key,并以解密後的key來代替(這裡也要求輸入之前設定的密碼):
openssl rsa -in server.key -out server_nopwd.key
生成服務端證書(server.cert)
openssl x509 -req -days 365 -in server.csr -signkey server_nopwd.key -out server.crt
完成這一步之後就得到了我們需要的證書檔案和私鑰了
server.crt
server_nopwd.key
配置nginx伺服器,支援https通路
server.crt 和server_nopwd.key檔案放到我們預先建立的SSL檔案夾下,我這裡是在SSL檔案夾下生成的,是以不用移動
修改配置檔案default.conf,添加一個server
server {
listen 443 ssl;
#配置HTTPS的預設通路端口443。
#如果未在此處配置HTTPS的預設通路端口,可能會造成Nginx無法啟動。
#如果你使用Nginx 1.15.0及以上版本,請使用listen 443 ssl代替listen 443和ssl on。
server_name localhosst; #證書綁定的域名
# 增加ssl
ssl_certificate /ssl/server.crt;
ssl_certificate_key /ssl/server_nopwd.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
# 指定密碼為openssl支援的格式
ssl_protocols SSLv2 SSLv3 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5; # 密碼加密方式
ssl_prefer_server_ciphers on; # 依賴SSLv3和TLSv1協定的伺服器密碼将優先于用戶端密碼
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
# 定義首頁索引目錄和名稱,nginx的預設首頁的html檔案,這個html可以自己定義一個,任意的都可以。
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#定義錯誤提示頁面
#error_page 404 /404.html;
#重定向錯誤頁面到 /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
docker restart nginx
通路HTTPS端口,如下所示。
Chrome中自簽證書不安全問題
可以參考 使用Openssl生成自簽證書這篇部落格,以下都是這位部落客的内容,這位部落客記錄的很詳細。
導入自簽CA憑證到作業系統
關于證書不安全的提示,是由于我們自簽名的CA憑證不是權威機構,作業系統不承認所導緻,可以将我們自己的CA安裝到作業系統中
在windows系統可通過運作certmgr.msc來檢視本地已安裝證書:
在導入ca證書後,浏覽器仍提示"不安全"
設定證書"使用者可選名稱SAN"
查詢相關資料後發現,新的chrome浏覽器需要為自簽證書設定SAN(使用者可選名稱,subject alternative name)
關于openssl設定SAN可以參考:使用openssl為ssl證書增加“使用者備用名稱(DNS)” 我在學習ssl階段使用的openssl指令,後續操作的時候都使用xca(一個生成證書的圖形化工具),在xca中設定SAN如下:
重新生成證書、重新加載配置後,可以發現此時浏覽器不再報"不安全"了,同時檢視證書可以發現"使用者可選名稱"已被添加
給購買域名添加SSL
給域名添加SSL也可以(更加友善),并且騰訊雲,阿裡雲之類的還會幫你生成對應域名的SSL,你下載下傳下來,拷貝到上面ssl/檔案,然後修改配置檔案就行
伺服器添加SSL
我這裡是騰訊雲,直接去騰訊雲搜尋框裡面搜尋SSL證書,然後申請證書
填寫資訊,證書綁定的域名(我這個域名已經解析到了伺服器位址,是部署nginx的伺服器,千萬别搞錯了,還是要通過域名去通路nginx服務的)
一系列的填寫資訊後就可以下載下傳證書了
下載下傳Nginx的證書
将下載下傳下來的檔案使用xftp軟體拷貝到伺服器挂載的檔案夾下面,也就是/usr/local/nginx/ssl 下面
修改default.conf配置檔案
server {
listen 443 ssl;
#配置HTTPS的預設通路端口443。
#如果未在此處配置HTTPS的預設通路端口,可能會造成Nginx無法啟動。
#如果你使用Nginx 1.15.0及以上版本,請使用listen 443 ssl代替listen 443和ssl on。
server_name www.xxx.club; #證書綁定的域名(換成你自己的)
# 增加ssl
ssl_certificate /ssl/TecentServer.pem #換成你自己的
ssl_certificate_key /ssl/TecentServer.key; #換成你自己的
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
# 指定密碼為openssl支援的格式
ssl_protocols SSLv2 SSLv3 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5; # 密碼加密方式
ssl_prefer_server_ciphers on; # 依賴SSLv3和TLSv1協定的伺服器密碼将優先于用戶端密碼
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
# 定義首頁索引目錄和名稱,nginx的預設首頁的html檔案,這個html可以自己定義一個,任意的都可以。
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#定義錯誤提示頁面
#error_page 404 /404.html;
#重定向錯誤頁面到 /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
重新啟動nginx容器服務
docker restart nginx
如圖所示,已經可以成功利用域名(HTTPS)來通路容器的nginx網頁。
後面的端口号不能忘(因為域名隻是對應到了IP位址,但是具體服務還是要通過端口号來找,但是80端口是預設的,是以可以省略)
關于ssl證書的坑
對于每一個不同的子域名,都需要去申請一個ssl證書。
比如說mail.xt.com,需要去申請一個ssl證書,對于www.xt.com,還需要去申請一個新的ssl證書。
那麼能不能申請一個通配的證書去适配一個主域名下的所有子域名呢。
有的,花錢。比如你可以申請一個*.xt.com的證書,那樣所有子域名就都能用這個證書了。
我的nginx的證書如下:一個域名一個證書
CSDN的SSL證書:
添加SSL失敗
在伺服器上安裝部署 SSL 證書後,使用 HTTPS 協定通路網站,頁面加載緩慢、空白或提示 “無法通路”。
可能原因
伺服器防火牆未開啟443端口:若您的伺服器防火牆未開啟443端口,将導緻您無法使用 HTTPS 正常通路您網站,請開啟伺服器443端口後,再進行嘗試。
安全組未開啟:安全組是一種虛拟防火牆,具備有狀态的資料包過濾功能,用于廠商設定雲伺服器、負載均衡、雲資料庫等執行個體的網絡通路控制,控制執行個體級别的出入流量,是重要的網絡安全隔離手段,預設情況下為關閉狀态。請開啟伺服器的安全組設定後,再進行嘗試。
浏覽器緩存污染:浏覽器緩存可以節約網絡資源加速浏覽,通常情況下浏覽器會對最近請求過的資源進行緩存。當通路者再次請求這個頁面時,浏覽器将可能會以已緩存資訊進行展示。
配置檔案未配置正确:伺服器的 Web 服務配置檔案未配置正确,導緻網站無法正确處理請求導緻網站無法通路。
解決辦法
伺服器防火牆未開啟443端口
若您使用的是騰訊雲的雲伺服器(CVM),您無需進行該項設定,雲伺服器(CVM)預設為開啟狀态,建議您檢查 安全組是否開啟。
若您使用的是騰訊雲輕量應用伺服器(Lighthouse),請參考 管理防火牆 開啟443端口設定。
若您使用的是其他雲廠商雲伺服器,請咨詢您的雲廠商。
安全組未開啟
若您使用的是騰訊雲的雲伺服器,請參考 添加安全組規則 開啟443端口。
若您使用的是騰訊雲輕量應用伺服器(Lighthouse),則無該功能設定,建議您檢查 防火牆是否開啟443端口。
若您使用的是其他雲廠商雲伺服器,請咨詢您的雲廠商是否有該政策,如有該政策,咨詢如何開啟443端口;如無該政策,建議您檢查 防火牆是否開啟443端口。不過我這裡不同,我是使用主控端映射的nginx容器的443端口,而容器内的端口都是預設開放的,是以我隻需要打開主控端的442端口
References:
- https://baike.baidu.com/item/nginx/3817705?fr=aladdin#1_1
- https://www.nginx.cn/nginxchswhyuseit
- https://www.runoob.com/docker/docker-install-nginx.html
- https://www.jianshu.com/p/5f9bd492f186
- https://cloud.tencent.com/document/product/400/53650