Nginx配置以及熱升級

FuShudi發表於2024-07-02

目錄
  • Nginx詳解
    • 1. Nginx關鍵特性
    • 2. Nginx配置
      • 2.1 event
      • 2.2 http
        • 2.2.1 log_format
        • 2.2.2 sendfile
        • 2.2.3 tcp_nopush
        • 2.2.4 tcp_nodelay
        • 2.2.5 keepalive_timeout
        • 2.2.6 include
        • 2.2.7 default_type
        • 2.2.8 server
    • 3. 配置Nginx虛擬主機
      • 3.1 基於埠
      • 3.2 基於IP
      • 3.3 基於域名
    • 4. Location
      • 4.1 拒絕訪問
      • 4.2 拒絕訪問test開頭的所有檔案
      • 4.3 忽略大小寫
      • 4.4 反向代理
    • 5. 配置https
    • 6. Nginx熱升級
      • 6.1 環境清理
      • 6.2 編譯安裝舊版本Nginx
      • 6.3 啟動舊版nginx
      • 6.4 下載新版nginx

Nginx詳解

Nginx與Apache一樣,都是web伺服器,但是Nginx比Apache多一些功能,比如Nginx可以做代理,可以做負載均衡……

1. Nginx關鍵特性

  • 支援高併發
    • 單機Nginx可支援十萬級別的併發連線,經過最佳化後可支援百萬級別併發
  • 記憶體資源消耗低
    • 在同級web中,Nginx佔用的記憶體最少,一萬非活躍的http長連線僅消耗2.5M記憶體
  • 高擴充套件性
    • 和Apache一樣,Nginx採用模組化設計,並支援非常多豐富的第三方模組
  • 高可靠性
    • Nginx採用master-worker模式,如果worker出現故障,master可以快速開啟一個新的worker來提供服務

2. Nginx配置

[root@ceph conf.d]# grep -Ev "^#|^$|#" /etc/nginx/nginx.conf |cat -n
     1	user nginx;
     2	worker_processes auto;
     3	error_log /var/log/nginx/error.log;
     4	pid /run/nginx.pid;
     5	include /usr/share/nginx/modules/*.conf;
     6	events {
     7	    worker_connections 1024;
     8	}
     9	http {
    10	    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    11	                      '$status $body_bytes_sent "$http_referer" '
    12	                      '"$http_user_agent" "$http_x_forwarded_for"';
    13	    access_log  /var/log/nginx/access.log  main;
    14	    sendfile            on;
    15	    tcp_nopush          on;
    16	    tcp_nodelay         on;
    17	    keepalive_timeout   65;
    18	    types_hash_max_size 4096;
    19	    include             /etc/nginx/mime.types;
    20	    default_type        application/octet-stream;
    21	    include /etc/nginx/conf.d/*.conf;
    22	    server {
    23	        listen       80;
    24	        listen       [::]:80;
    25	        server_name  _;
    26	        root         /usr/share/nginx/html;
    27	        include /etc/nginx/default.d/*.conf;
    28	        error_page 404 /404.html;
    29	            location = /40x.html {
    30	        }
    31	        error_page 500 502 503 504 /50x.html;
    32	            location = /50x.html {
    33	        }
    34	    }
    35	}

由於之前很詳細的寫過Apache的配置了,這裡就說一下這倆服務之間的差異,nginx的配置檔案每行配置結束必須以分號;結尾

  1. Nginx也可以配置啟動的使用者,預設為nginx,可以修改
  2. Nginx工作程序,預設為auto(與CPU核心數保持一致),也可以手動修改
  3. 定義nginx的錯誤日誌

這兩個都是Apache服務裡面也有的,這裡就簡答說一下

2.1 event

第六行event這個是指定nginx的工作模式,預設的,Apache也有這個模式,這個段落裡面的內容

events {
worker_connections 1024; 指定單個程序的連線數
}

2.2 http

這個段落裡面就是一些http的配置

2.2.1 log_format

首先就是定義日誌的格式log_format,然後就是access.log這個就不細寫

2.2.2 sendfile

sendfile on;這個代表高效傳輸,也就是可以將檔案直接從磁碟傳輸到網路中,而不先讀到記憶體

2.2.3 tcp_nopush

tcp_nopush on 立刻回應tcp的請求

2.2.4 tcp_nodelay

tcp_nodelay on 對於小資料包直接回應

2.2.5 keepalive_timeout

keepalive_timeout 65,這個透過名字就可以知道,是長連線的超時時間

2.2.6 include

我跳過了types_hash_max_size,這個是hash雜湊表,我也不知道是幹嘛的

include /etc/nginx/mime.types; 這裡是載入nginx能夠識別的型別,你可以開啟這個檔案去看這裡面都定義了什麼,開啟就一目瞭然了

2.2.7 default_type

default_type application/octet-stream; 二進位制的檔案可以直接下載

2.2.8 server

server {
listen 80;
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}

這裡的server對應的就是Apache的虛擬主機

listen 監聽的埠,他這裡預設監聽了2個,一個是IPv4,另一個是IPv6

server_name:對外提供的服務名,也就是域名

root:網站根目錄

include: 定義虛擬主機的特性,可以將一些其他的特性解除安裝conf.d/下之後他會自動載入配置

error_page 404 :這個是錯誤頁,當404出現的時候,nginx會返回網站根目錄下的404.html

locatioin: 這個是nginx的重頭戲,叫做路由規則,你可以將路由策略寫在這,他就會根據你的策略來處理流量,這個我們稍後細講

error_page 500當服務發生500以上的錯誤的時候,nginx返回網站根目錄下的50x.html

3. 配置Nginx虛擬主機

Nginx也支援3種虛擬主機,與Apache一樣

  • 基於埠的虛擬主機
  • 基於IP的虛擬主機
  • 基於域名的虛擬主機

3.1 基於埠

虛擬主機我們可以在conf.d下進行配置

[root@ceph conf.d]# vim virthost.conf
server {
  listen 81;
  root /web1;
}

server {
  listen 82;
  root /web2;
}
[root@ceph conf.d]# echo 81 > /web1/index.html
[root@ceph conf.d]# echo 82 > /web2/index.html
[root@ceph conf.d]# systemctl restart nginx
[root@ceph conf.d]# curl localhost:82
82
[root@ceph conf.d]# curl localhost:81
81

基於埠的虛擬主機這樣就配好了

3.2 基於IP

首先配置一個臨時IP

[root@ceph conf.d]# sudo ip addr add 192.168.1.100/24 dev ens33
[root@ceph conf.d]# ip a |grep 192.168.1.100
    inet 192.168.1.100/24 scope global ens33

虛擬的IP就配置好了,接下來配置nginx

[root@ceph conf.d]# vim virthost.conf 
server {
  listen 81;
  root /web1;
}

server {
  listen 82;
  root /web2;
}

server {
  listen 192.168.200.210:80;
  root /web3;
}

server {
  listen 192.168.1.100:80;
  root /web4;
}

然後我們建立對應的網站根目錄以及index.html

[root@ceph conf.d]# echo 192.168.200.210 > /web3/index.html
[root@ceph conf.d]# echo 192.168.1.100 > /web4/index.html
[root@ceph conf.d]# systemctl restart nginx
[root@ceph conf.d]# curl 192.168.200.210
192.168.200.210
[root@ceph conf.d]# curl 192.168.1.100
192.168.1.100

可以看到,透過不同的ip訪問回顯是不同的內容

3.3 基於域名

[root@ceph conf.d]# vim virthost.conf 
server {
  listen 80;
  server_name test.com;
  root /web5;
}

server {
  listen 80;
  server_name example.com;
  root /web6;
}

建立根目錄以及重啟服務,還需要做hosts解析

[root@ceph conf.d]# echo web5 > /web5/index.html
[root@ceph conf.d]# echo web6 > /web6/index.html
[root@ceph conf.d]# systemctl restart nginx
[root@ceph conf.d]# vim /etc/hosts
192.168.200.210 test.com
192.168.200.210 example.com
[root@ceph conf.d]# curl test.com
web5
[root@ceph conf.d]# curl example.com
web6

這樣也是可以訪問到對應的檔案的

4. Location

這個是nginx最重要的配置了,在Apache裡面訪問控制是用DirectoryFiles來做的,那麼在nginx裡面的做法就是location了

4.1 拒絕訪問

我不想你訪問網站根目錄下的/test.html,那麼我的路由規則就應該這樣寫,還是在虛擬主機裡定義

[root@ceph conf.d]# vim virthost.conf 
server {
  listen 80;
  server_name test.com;
  root /web5;
  location /test.html {
    return 403;
  }
}

我們來建立這個test.html檔案,並嘗試訪問

[root@ceph conf.d]# echo "test file" > /web5/test.html
[root@ceph conf.d]# systemctl restart nginx
[root@ceph conf.d]# curl 192.168.200.210/test.html
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

看到了嗎?他就返回的是403,這樣做之後,訪問test.html的請求就被拒絕掉了,但是如果我們需要拒絕掉所有以test開頭的檔案呢?也是跟Apache一樣使用 * 號嗎?不,Nginx是另外的做法

4.2 拒絕訪問test開頭的所有檔案

[root@ceph conf.d]# vim virthost.conf
server {
  listen 80;
  server_name test.com;
  root /web5;
  location ^~ /test {
    return 403;
  }
}
[root@ceph conf.d]# echo test > /web5/test.1
[root@ceph conf.d]# echo test > /web5/test.2
[root@ceph conf.d]# systemctl restart nginx

我們在/web5下建立了test.1和test.2包括之前建立的test.html一共有3個test開頭的檔案,那我們現在來嘗試訪問一下

[root@ceph conf.d]# curl 192.168.200.210/test.html -I 
HTTP/1.1 403 Forbidden
Server: nginx
Date: Tue, 02 Jul 2024 09:09:49 GMT
Content-Type: text/html
Content-Length: 146
Connection: keep-alive

[root@ceph conf.d]# curl 192.168.200.210/test.1 -I 
HTTP/1.1 403 Forbidden
Server: nginx
Date: Tue, 02 Jul 2024 09:09:56 GMT
Content-Type: text/html
Content-Length: 146
Connection: keep-alive
[root@ceph conf.d]# curl 192.168.200.210/test.xxx -I 
HTTP/1.1 403 Forbidden
Server: nginx
Date: Tue, 02 Jul 2024 09:10:12 GMT
Content-Type: text/html
Content-Length: 146
Connection: keep-alive

看到了吧,儘管我們訪問一個不存在的檔案,按道理應該是返回404,但是這個檔案是以test開頭,那麼他會被拒絕訪問,不管這個檔案存不存在

但是這樣配置,只能拒絕掉以test開頭的,我如果訪問的是Test,那麼他就不會被拒絕了

[root@ceph conf.d]# curl 192.168.200.210/Test -I 
HTTP/1.1 404 Not Found
Server: nginx
Date: Tue, 02 Jul 2024 09:12:57 GMT
Content-Type: text/html
Content-Length: 146
Connection: keep-alive

對吧,因為我們沒有這個資源,所以他返回了404,而不是403,說明沒有被拒絕,如果想忽略大小寫,可以這樣做

4.3 忽略大小寫

[root@ceph conf.d]# vim virthost.conf 
server {
  listen 80;
  server_name test.com;
  root /web5;
  location ~* /test {
    return 403;
  }
}

只需要將^~這個地方改為~*,我們來訪問一下看看

[root@ceph conf.d]# curl -I 192.168.200.210/test
HTTP/1.1 403 Forbidden
Server: nginx
Date: Tue, 02 Jul 2024 09:15:17 GMT
Content-Type: text/html
Content-Length: 146
Connection: keep-alive

[root@ceph conf.d]# curl -I 192.168.200.210/Test
HTTP/1.1 403 Forbidden
Server: nginx
Date: Tue, 02 Jul 2024 09:15:21 GMT
Content-Type: text/html
Content-Length: 146
Connection: keep-alive

[root@ceph conf.d]# curl -I 192.168.200.210/TEst
HTTP/1.1 403 Forbidden
Server: nginx
Date: Tue, 02 Jul 2024 09:15:23 GMT
Content-Type: text/html
Content-Length: 146
Connection: keep-alive

現在的配置,不管你的大寫的TEST還是小寫的test,亦或者是大小寫都有的,一律都會被拒絕訪問

4.4 反向代理

我們還可以透過location來做反向代理,比如你現在訪問我網站下的/那我就直接給你代理到baidu.com去,你要搜尋啥你自己去搜吧,你以為這個百度是我給你提供的,其實不然,我是把你的請求給到百度了

[root@ceph conf.d]# vim virthost.conf 
server {
  listen 80;
  server_name test.com;
  root /web5;
  location  / {
    proxy_pass https://www.baidu.com;
  }
}

看到了嗎?這是貨真價實的百度哦,可以搜尋內容的

怎麼樣,你現在就搭建了一個反向代理,客戶端只知道他訪問的是192.168.200.210這個IP,他並不知道你把他的請求給了百度,所以客戶端會以為你就是百度

5. 配置https

nginx配置https的方式其實跟Apache是差不多的,直接告訴他你的金鑰檔案放在哪,有2種方式可以配置https,第一種是直接改主配置檔案,主配置檔案裡是有https段落的,只不過預設被註釋了。

第二種方式就是自己寫一個虛擬主機,我這裡直接修改主配置檔案

[root@ceph nginx]# vim nginx.conf
    server {
        listen       443 ssl http2;
        listen       [::]:443 ssl http2;
        server_name  _;
        root         /usr/share/nginx/html;

        ssl_certificate "/etc/nginx/server.crt";
        ssl_certificate_key "/etc/nginx/server.key";

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }

將這一段的註釋全部給放開,ssl只保留需要的這2行內容,然後將證書地址改為你的證書的實際目錄就可以了,然後重啟nginx服務

6. Nginx熱升級

Nginx熱升級是指可以做到不停機升級Nginx的版本,yum安裝的Nginx是不支援熱升級的,如果想要熱升級Nginx,那麼你的Nginx必須是原始碼編譯安裝的

編譯安裝流程:

  1. 下載原始碼包
  2. 解壓原始碼包
  3. 執行預編譯 ./configure
  4. 編譯 make
  5. 編譯安裝 make install

這是編譯安裝的流程

在執行到第5步的時候,他就會將編譯好的二進位制檔案放在objs目錄下,就是依賴於這個目錄下的二進位制檔案我們才可以做到版本共存

nginx的熱升級原理主要依賴於以下幾個關鍵步驟:

  1. 啟動新版本的nginx程序:在進行熱升級時,首先啟動一個新版本的nginx程序,這個程序會使用新的配置檔案和程式檔案。
  2. 舊版本nginx程序繼續服務:啟動新版本nginx程序後,舊版本的nginx程序仍然繼續執行,繼續處理客戶端的請求。
  3. 新舊版本的協調切換:新版本nginx程序啟動後,會逐漸接管處理新的客戶端請求。同時,舊版本nginx程序在處理完當前已有的請求後逐漸退出。
  4. 共享監聽埠:新舊版本的nginx程序可以透過共享監聽的網路埠來實現平滑過渡。在大多數情況下,nginx會採用SO_REUSEPORT選項來允許多個程序監聽同一個埠。
  5. 無縫切換:由於新舊版本nginx程序可以並行執行並共享埠,因此在沒有中斷服務的情況下完成從舊版本到新版本的切換,實現了熱升級。

6.1 環境清理

如果你已經使用yum安裝了,先解除安裝nginx

[root@ceph ~]# yum remove -y nginx

6.2 編譯安裝舊版本Nginx

Nginx下載地址

在這裡面找一個相對舊一點的版本,我這裡下載一個1.26.1,然後將1.26.1升級到1.27.0

[root@ceph ~]# cd /opt/
[root@ceph opt]# wget https://nginx.org/download/nginx-1.26.1.tar.gz
[root@ceph opt]# tar -zxf nginx-1.26.1.tar.gz 
[root@ceph opt]# cd nginx-1.26.1/
[root@ceph nginx-1.26.1]# ls
auto     CHANGES.ru  configure  html     man     src
CHANGES  conf        contrib    LICENSE  README
[root@ceph nginx-1.26.1]# ./configure --prefix=/usr/local/nginx

在這裡執行的時候他可能會報錯,根據他的報錯你安裝相對應的軟體包就好了

Configuration summary
  + using system PCRE2 library
  + OpenSSL library is not used
  + using system zlib library

  nginx path prefix: "/usr/local/nginx"
  nginx binary file: "/usr/local/nginx/sbin/nginx"
  nginx modules path: "/usr/local/nginx/modules"
  nginx configuration prefix: "/usr/local/nginx/conf"
  nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
  nginx pid file: "/usr/local/nginx/logs/nginx.pid"
  nginx error log file: "/usr/local/nginx/logs/error.log"
  nginx http access log file: "/usr/local/nginx/logs/access.log"
  nginx http client request body temporary files: "client_body_temp"
  nginx http proxy temporary files: "proxy_temp"
  nginx http fastcgi temporary files: "fastcgi_temp"
  nginx http uwsgi temporary files: "uwsgi_temp"
  nginx http scgi temporary files: "scgi_temp"

他執行完之後會這樣輸出就是沒有錯誤,可以繼續往下做

[root@ceph nginx-1.26.1]# make -j 4
  • -j 指定並行編譯的程序數為4
[root@ceph nginx-1.26.1]# make install

6.3 啟動舊版nginx

由於我們指定的安裝路徑是/usr/local/nginx,所以他會在這個目錄下生成一個sbin的目錄,這個目錄裡面有一個二進位制檔案nginx,執行他就可以啟動nginx

[root@ceph nginx-1.26.1]# cd /usr/local/nginx/sbin/
[root@ceph sbin]# ./nginx 
[root@ceph sbin]# curl -I 192.168.200.210 
HTTP/1.1 200 OK
Server: nginx/1.26.1
Date: Tue, 02 Jul 2024 11:27:47 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 02 Jul 2024 11:25:09 GMT
Connection: keep-alive
ETag: "6683e395-267"
Accept-Ranges: bytes

在server這一欄我們可以看見nginx的版本是1.26.1

6.4 下載新版nginx

現在我們將nginx升級到1.27.0

[root@ceph sbin]# cd /opt/
[root@ceph opt]# wget https://nginx.org/download/nginx-1.27.0.tar.gz
[root@ceph opt]# tar -zxf nginx-1.27.0.tar.gz
[root@ceph opt]# cd nginx-1.27.0/
[root@ceph nginx-1.27.0]# ./configure --prefix=/usr/local/nginx 
[root@ceph nginx-1.27.0]# make -j 4

這裡非常需要注意,一定不要去執行make install了,因為執行這個命令的話會將原來的nginx全部覆蓋掉,我們只需要替換掉nginx的二進位制檔案就好了

我們來到objs目錄

[root@ceph nginx-1.27.0]# ls
auto     CHANGES.ru  configure  html     Makefile  objs    src
CHANGES  conf        contrib    LICENSE  man       README
[root@ceph nginx-1.27.0]# cd objs/
[root@ceph objs]# ls
autoconf.err  nginx    ngx_auto_config.h   ngx_modules.c  src
Makefile      nginx.8  ngx_auto_headers.h  ngx_modules.o

這裡面就有一個nginx的二進位制檔案,先彆著急啟動,我們先將老版本的nginx二進位制檔案進行備份

[root@ceph objs]# cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak
[root@ceph objs]# cd /usr/local/nginx/sbin/
[root@ceph sbin]# cp /opt/nginx-1.27.0/objs/nginx .
cp: overwrite './nginx'? y
[root@ceph sbin]# ./nginx -v
nginx version: nginx/1.27.0

現在我們就已經將1.27.0的二進位制檔案複製到這個地方來了,接下來我們需要將nginx1.27.0也給啟動起來。

你這時候可能會有疑問,80埠不是已經被老版本的nginx給佔用了嗎,我現在在啟動不會報錯嗎?答案肯定是會,所以我們在啟動之前還需要進行一個操作,給老版本的nginx'傳送一個USR2的訊號

[root@ceph sbin]# ps -ef |grep nginx
root       46538       1  0 19:27 ?        00:00:00 nginx: master process ./nginx
nobody     46539   46538  0 19:27 ?        00:00:00 nginx: worker process
root       49680   15412  0 19:36 pts/0    00:00:00 grep --color=auto nginx

我們查到nginx master的程序id是46538,接下來就是發訊號了

[root@ceph sbin]# kill -s USR2 46538
# 然後我們再啟動nginx
[root@ceph sbin]# ps -ef |grep nginx
root       46538       1  0 19:27 ?        00:00:00 nginx: master process ./nginx
nobody     46539   46538  0 19:27 ?        00:00:00 nginx: worker process
root       49708   46538  0 19:37 ?        00:00:00 nginx: master process ./nginx
nobody     49709   49708  0 19:37 ?        00:00:00 nginx: worker process
root       49761   15412  0 19:38 pts/0    00:00:00 grep --color=auto nginx

看到了嗎?除了老版本的46538之外,還有一個新的nginx master程序,49708

嘗試訪問

[root@ceph sbin]# curl 192.168.200.210 -I 
HTTP/1.1 200 OK
Server: nginx/1.27.0
Date: Tue, 02 Jul 2024 11:39:04 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 02 Jul 2024 11:25:09 GMT
Connection: keep-alive
ETag: "6683e395-267"
Accept-Ranges: bytes

看,他現在處理連線的版本就是1.27.0了,如果老版本的nginx還有連線在處理的話也是不會受到影響的,等我們確認沒問題之後我們只需要將老版本給kill掉

[root@ceph sbin]# kill 46538
[root@ceph sbin]# ps -ef |grep nginx
root       49708       1  0 19:37 ?        00:00:00 nginx: master process ./nginx
nobody     49709   49708  0 19:37 ?        00:00:00 nginx: worker process
root       49913   15412  0 19:40 pts/0    00:00:00 grep --color=auto nginx

這個時候老版本就成功退役了,所有的連線都交由新版本的nginx來處理,我們的熱升級就搞定了

相關文章