nginx之從main函數(shù)開始了解配置文件處理及配置信息的讀入過程
nginx配置文件相關(guān)的參數(shù)保存在以下幾個成員中,從main函數(shù)(nginx.c中)開始,一步一步查看ngx_cycle_s 中與配置相關(guān)的成員是如何賦值的:
struct ngx_cycle_s {
void ****conf_ctx;
...
ngx_str_t conf_file;
ngx_str_t conf_param;
ngx_str_t conf_prefix;
ngx_str_t prefix;
...
};
一:ngx_process_options 函數(shù),忽略其他不相干部分
static ngx_int_t
ngx_process_options(ngx_cycle_t *cycle)
{
u_char *p;
size_t len;
if (ngx_prefix) {
//如果執(zhí)行命令時指定路徑,就會進(jìn)入這個條件,所以省略了
//例如 ./nginx -p /home/dmj
....
} else {
...
//NGX_CONF_PREFIX = "/conf"
ngx_str_set(&cycle->conf_prefix, NGX_CONF_PREFIX);
//NGX_PREFIX = "usr/local/nginx"
ngx_str_set(&cycle->prefix, NGX_PREFIX);
}
if (ngx_conf_file) {
cycle->conf_file.len = ngx_strlen(ngx_conf_file);
cycle->conf_file.data = ngx_conf_file;
} else {
//NGX_CONF_PATH= "conf/nginx.conf"
ngx_str_set(&cycle->conf_file, NGX_CONF_PATH);
}
//合并前綴路徑與文件名得到此時cycle->conf_file = "/usr/local/nginx//conf/nginx.conf"
if (ngx_conf_full_name(cycle, &cycle->conf_file, 0) != NGX_OK) {
return NGX_ERROR;
}
//cycle->conf_prefix 指向 cycle->conf_file 也為"/usr/local/nginx//conf/nginx.conf"
//但是該指針長度只取了前綴路徑部分"/usr/local/nginx//conf/"
for (p = cycle->conf_file.data + cycle->conf_file.len - 1;
p > cycle->conf_file.data;
p--)
{
if (ngx_path_separator(*p)) {
cycle->conf_prefix.len = p - cycle->conf_file.data + 1;
cycle->conf_prefix.data = cycle->conf_file.data;
break;
}
}
....
return NGX_OK;
}
經(jīng)過上訴代碼,至此將ngx_cycle_s 中配置文件路徑相關(guān)的成員賦值了,此時conf_param及 conf_ctx未賦值
struct ngx_cycle_s {
void ****conf_ctx;
...
ngx_str_t conf_file; //“usr/local/nginx//conf/nginx.conf”
ngx_str_t conf_param;
ngx_str_t conf_prefix; //“usr/local/nginx//conf/
ngx_str_t prefix; //"usr/local/nginx"
...
};
二:先不管conf_param,著重看下conf_ctx成員
他是一個4級指針,里面包含了所有配置文件的配置信息,也就是說nginx.conf 文件中的內(nèi)容,經(jīng)過解析后都會保存到conf_ctx 指針
2.1 ngx_preinit_modules函數(shù)
功能如下:
- 給ngx_modules 中的模塊的 name , index賦值
- 同時統(tǒng)計模塊總數(shù) 靜態(tài)全局 ngx_modules數(shù)組大小+NGX_MAX_DYNAMIC_MODULES(定義為128)
ngx_modules大小與conf_ctx指向的數(shù)組大小一致,后面會有提到,因此先簡單說明下其初始化的時候
ngx_int_t
ngx_preinit_modules(void)
{
ngx_uint_t i;
for (i = 0; ngx_modules[i]; i++) {
ngx_modules[i]->index = i;
ngx_modules[i]->name = ngx_module_names[i];
}
ngx_modules_n = i;
ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES;
return NGX_OK;
}
2.2 ngx_init_cycle函數(shù)
在這里做了很多初始化的操作,函數(shù)太長,這里只截取函數(shù)內(nèi)與配置相關(guān)的代碼
2.2.1 conf_ctx 分配內(nèi)存,大小與模塊個數(shù)相同的,ngx_max_module 就是模塊的總數(shù)(靜態(tài) 數(shù)組 + 動態(tài)大小128)
cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
if (cycle->conf_ctx == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
2.2.2 將靜態(tài)數(shù)組ngx_modules 拷貝進(jìn)cycle->modules,此時還有動態(tài)的128個沒有模塊數(shù)據(jù)
ngx_int_t
ngx_cycle_modules(ngx_cycle_t *cycle)
{
/*
* create a list of modules to be used for this cycle,
* copy static modules to it
*/
cycle->modules = ngx_pcalloc(cycle->pool, (ngx_max_module + 1)
* sizeof(ngx_module_t *));
if (cycle->modules == NULL) {
return NGX_ERROR;
}
ngx_memcpy(cycle->modules, ngx_modules,
ngx_modules_n * sizeof(ngx_module_t *));
cycle->modules_n = ngx_modules_n;
return NGX_OK;
}
2.2.3 調(diào)用create_conf 函數(shù)為核心模塊創(chuàng)建配置結(jié)構(gòu)體,那非核心模塊呢?
for (i = 0; cycle->modules[i]; i++) {
//非核心模塊,查找下一個模塊
if (cycle->modules[i]->type != NGX_CORE_MODULE) {
continue;
}
module = cycle->modules[i]->ctx;
if (module->create_conf) {
rv = module->create_conf(cycle);//創(chuàng)建一個默認(rèn)值的ngx_core_conf_t
if (rv == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
cycle->conf_ctx[cycle->modules[i]->index] = rv;//將配置結(jié)構(gòu)體放入配置項列表
}
}
下表為nginx定義模塊類型為NGX_CORE_MODULE的模塊,此時因?yàn)閏ycle->modules只有靜態(tài)數(shù)組中的模塊,而下面表格所列只有ngx_core_module和ngx_regex_module在靜態(tài)數(shù)組中,因此
| 核心模塊 | 創(chuàng)建配置結(jié)構(gòu)體接口實(shí)現(xiàn) | 配置結(jié)構(gòu)體類型 |
|---|---|---|
| ngx_core_module | ngx_core_module_create_conf | ngx_core_conf_t |
| ngx_errlog_module | 無 | 無 |
| ngx_regex_module | ngx_regex_create_conf | ngx_regex_conf_t |
| ngx_openssl_module | ngx_openssl_create_conf | ngx_openssl_conf_t |
| ngx_events_module | 無 | 無 |
| ngx_http_module | 無 | 無 |
| ngx_mail_module | 無 | 無 |
| ngx_google_perftools_module | ngx_google_perftools_create_conf | ngx_google_perftools_conf_t |
| ngx_stream_module | 無 | 無 |
此時內(nèi)存大概是這樣分布,其余的都還只是指針,未指向特定結(jié)構(gòu)體

2.2.4 調(diào)用ngx_conf_parse函數(shù),解析配置文件
conf.ctx = cycle->conf_ctx; //配置結(jié)構(gòu)體列表
conf.cycle = cycle;
conf.pool = pool;
conf.log = log;
conf.module_type = NGX_CORE_MODULE;
conf.cmd_type = NGX_MAIN_CONF;
if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
environ = senv;
ngx_destroy_cycle_pools(&conf);
return NULL;
}
三:這個函數(shù)很重要,單獨(dú)拎出來說明
ngx_conf_parse全部內(nèi)容就不貼了,貼幾個關(guān)鍵代碼:
char *
ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
{
....
//打開文件,并將文件信息放入cf
if (filename) {
/* open configuration file */
fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
...
cf->conf_file->file.fd = fd;
cf->conf_file->file.name.len = filename->len;
cf->conf_file->file.name.data = filename->data;
cf->conf_file->file.offset = 0;
cf->conf_file->file.log = cf->log;
cf->conf_file->line = 1;
type = parse_file;
...
//循環(huán)讀取文件內(nèi)容
for ( ;; ) {
/******************************************
1.讀取文件內(nèi)容,每次讀取一個buf大小(4K),如果文件內(nèi)容不足4K則全部讀取到buf中.
2.掃描buf中的內(nèi)容,每次掃描一個token就會存入cf->args中,然后返回.
3.返回后調(diào)用ngx_conf_parse函數(shù)會調(diào)用*cf->handler和ngx_conf_handler(cf, rc)函數(shù)處理.
3.如果是復(fù)雜配置項,會調(diào)用上次執(zhí)行的狀態(tài)繼續(xù)解析配置文件.
*****************************************/
rc = ngx_conf_read_token(cf);
/*
* ngx_conf_read_token() may return
*
* NGX_ERROR there is error
* NGX_OK the token terminated by ";" was found
* NGX_CONF_BLOCK_START the token terminated by "{" was found
* NGX_CONF_BLOCK_DONE the "}" was found
* NGX_CONF_FILE_DONE the configuration file is done
*/
if (rc == NGX_ERROR) {
goto done;
}
//循環(huán)結(jié)束
if (rc == NGX_CONF_BLOCK_DONE) {
goto done;
}
//循環(huán)結(jié)束
if (rc == NGX_CONF_FILE_DONE) {
goto done;
}
/* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */
//cf->handler初始為空,需要在ngx_conf_handler配置
if (cf->handler) {
/*
* the custom handler, i.e., that is used in the http's
* "types { ... }" directive
*/
rv = (*cf->handler)(cf, NULL, cf->handler_conf);
if (rv == NGX_CONF_OK) {
continue;
}
...
}
//常規(guī)內(nèi)容處理
rc = ngx_conf_handler(cf, rc);
if (rc == NGX_ERROR) {
goto failed;
}
}
...
}
代碼包含2部分:
- 上半部分,文件信息讀入
- 下半部分,循環(huán)遍歷文件內(nèi)容
前面部分已經(jīng)描述了,配置文件路徑是如何得到的,在這里重新將文件信息賦值進(jìn)ngx_conf_t 結(jié)構(gòu)體 cf中,以便傳入后面的函數(shù)去讀取文件內(nèi)容,不多描述,講下第2點(diǎn)循環(huán)遍歷文件內(nèi)容,這里有幾個關(guān)鍵點(diǎn)
- 循環(huán)何時退出?
- 內(nèi)容如何讀???
- 內(nèi)容如何放入全局的conf_ctx中
3.1 循環(huán)何時退出?
從for ( ;; ) 代碼開始看,正常的情況下是在塊結(jié)束(rc == NGX_CONF_BLOCK_DONE也就是 字符"}")和文件結(jié)束(rc == NGX_CONF_FILE_DONE)時退出,文件讀取結(jié)束退出理解,但是塊結(jié)束怎么就退出了?
塊中不還有塊嗎?類似下圖這種,道理也很簡單,塊里面讀取過程都一樣,是一種遞歸的調(diào)用,塊里面遇到塊會繼續(xù)調(diào)用ngx_conf_parse函數(shù),只是nginx把這些過程都放到模塊的接口去了

3.2 內(nèi)容如何讀取
ngx_conf_read_token就是對文件內(nèi)容的讀取,上面代碼也有注釋,
讀取文件內(nèi)容,每次讀取一個buf大小(4K),如果文件內(nèi)容不足4K則全部讀取到buf中.掃描buf中的內(nèi)容,每次掃描一個token就會存入cf->args中,然后返回.
掃描buf中的內(nèi)容,每次掃描一個token就會存入cf->args中,然后返回.
什么情況下回返回呢?
- - 讀到了一個配置項,比如(模塊內(nèi)也一樣): “worker_processes 1;” 、 “index index.html index.htm;”
- - 讀到了一個模塊名,比如:“http { "
- - 塊結(jié)束,比如:”}"
返回后調(diào)用ngx_conf_parse函數(shù)會調(diào)用*cf->handler和ngx_conf_handler(cf, rc)函數(shù)處理.
如果是復(fù)雜配置項,會調(diào)用上次執(zhí)行的狀態(tài)繼續(xù)解析配置文件.
所以一次讀一個token出來,也就是一個配置項,放入cf->args
3.3 內(nèi)容如何放入全局的conf_ctx中?
我們來看ngx_conf_handler函數(shù),也只貼重要部分
static ngx_int_t
ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
{
char *rv;
void *conf, **confp;
ngx_uint_t i, found;
ngx_str_t *name;
ngx_command_t *cmd;
//cf->args->elts 不是包含了配置項的名字和值嗎?為什么可以取到名字?
//因?yàn)閏f->args->elts是一個鏈表,首節(jié)點(diǎn)就是配置項名字,并且每個元素都以'\0'結(jié)尾了
name = cf->args->elts;
found = 0;
//遍歷模塊
for (i = 0; cf->cycle->modules[i]; i++) {
cmd = cf->cycle->modules[i]->commands;
if (cmd == NULL) {
continue;
}
//遍歷模塊的配置項
for ( /* void */ ; cmd->name.len; cmd++) {
if (name->len != cmd->name.len) {
continue;
}
//匹配配置項的名字
if (ngx_strcmp(name->data, cmd->name.data) != 0) {
continue;
}
found = 1;
if (cf->cycle->modules[i]->type != NGX_CONF_MODULE
&& cf->cycle->modules[i]->type != cf->module_type)
{
continue;
}
/* is the directive's location right ? */
//匹配配置項的類型
if (!(cmd->type & cf->cmd_type)) {
continue;
}
...
/* set up the directive's configuration context */
conf = NULL;
if (cmd->type & NGX_DIRECT_CONF) {
conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index];
} else if (cmd->type & NGX_MAIN_CONF) {
conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);
} else if (cf->ctx) {
confp = *(void **) ((char *) cf->ctx + cmd->conf);
if (confp) {
conf = confp[cf->cycle->modules[i]->ctx_index];
}
}
rv = cmd->set(cf, cmd, conf);
...
}
}
...
}
函數(shù)邏輯也很簡單,遍歷所有模塊的所有配置項,比如配置文件讀取到deamon off;時,或 讀取master_process時

就會找到ngx_core_module模塊及其配置項ngx_core_commands

找到后,根據(jù)配置項類型從全局conf_ctx中取出指針,該指針指向包含存儲該配置項信息的結(jié)構(gòu)體,然后調(diào)用模塊配置項的接口set函數(shù),處理該信息,set接口會如何處理?繼續(xù)往下看
四 以http塊信息讀取來說明set的作用
一般來說信息會存儲到指定的配置結(jié)構(gòu)體中,比如deamon,master_process,會將其信息存入ngx_core_conf_t

經(jīng)過之前的代碼引入和說明,我們可以簡潔的將ngx_conf_parse函數(shù)調(diào)用過程貼出來
1、ngx_conf_parse
for ( ;; ) {
rc = ngx_conf_read_token(cf);
//常規(guī)內(nèi)容處理
rc = ngx_conf_handler(cf, rc);
}
2、ngx_conf_handler,conf的取值可能不同,第一次看有點(diǎn)繞,但是沒關(guān)系,你只要明白這玩意的目的是為了取出對應(yīng)的配置結(jié)構(gòu)體就行,然后set的目的就是設(shè)置該結(jié)構(gòu)體的信息
...
if (cmd->type & NGX_DIRECT_CONF)
{
conf = ((void **)cf->ctx)[cf->cycle->modules[i]->index];
}
else if (cmd->type & NGX_MAIN_CONF)
{
conf = &(((void **)cf->ctx)[cf->cycle->modules[i]->index]);
}
else if (cf->ctx)
{
confp = *(void **)((char *)cf->ctx + cmd->conf);
if (confp)
{
conf = confp[cf->cycle->modules[i]->ctx_index];
}
}
rv = cmd->set(cf, cmd, conf);
...
4.1 當(dāng)讀取到http時,遍歷模塊及其配置項,調(diào)用其set接口

依上圖及源碼,會調(diào)用ngx_http_block函數(shù)來處理http這個配置信息,其函數(shù)如下:
static char * ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
調(diào)用函數(shù)前,先搞清楚其傳參,如下圖,前2個參數(shù)好理解,后一個參數(shù)是什么意思?前面也說了是找出其配置結(jié)構(gòu)體的位置指針

可以這樣理解,conf指向conf_ctx的第7個元素

繼續(xù)了解ngx_http_block函數(shù),從源碼可以看出該函數(shù)做了以下幾件事
4.1.1 ngx_http_conf_ctx_t結(jié)構(gòu)體的分配,如下圖代碼所示,注意此時的conf就是上圖紅框標(biāo)識的conf

此時conf_ctx 內(nèi)存如下圖,此時 http配置項的結(jié)構(gòu)體已經(jīng)掛到全局conf_ctx上來了

4.1.2 統(tǒng)計http模塊個數(shù),并為每個http模塊ctx_index賦值

4.1.3 為ngx_http_conf_ctx_t結(jié)構(gòu)體的3個成員的分配內(nèi)存,有多少個http模塊就分配多少個指針給其成員,為什么要這么分配?
typedef struct {
void **main_conf;
void **srv_conf;
void **loc_conf;
} ngx_http_conf_ctx_t;
4.1.4 為每個http模塊創(chuàng)建其配置結(jié)構(gòu)體,與為全局conf_ctx分配內(nèi)存,創(chuàng)建配置結(jié)構(gòu)體一樣,都是其數(shù)組內(nèi)部指針指向不同的結(jié)構(gòu)體,而這些結(jié)構(gòu)體就是為了保持配置文件中的信息,內(nèi)存分配如下圖,篇幅有限只顯示了前幾個http模塊,注意:這里的索引就是第2步中模塊的ctx_index

4.1.5 繼續(xù)解析http塊內(nèi)的配置信息,調(diào)用ngx_conf_parse函數(shù)
過程大致與“第三”大節(jié)一樣,此時有幾個變量要注意,其中ctx 就是上圖的ngx_http_conf_ctx_t,模塊類型和配置類型都變了,如下代碼:
cf->ctx = ctx;
cf->module_type = NGX_HTTP_MODULE;
cf->cmd_type = NGX_HTTP_MAIN_CONF;
rv = ngx_conf_parse(cf, NULL);
最后調(diào)用ngx_conf_handler函數(shù)時,

看起來沒變化,其實(shí)上圖中
- cf->ctx為ngx_http_conf_ctx_t
- cf->cmd_type = NGX_HTTP_MAIN_CONF
因此最終conf=confp[cf->cycle->modules[i]->ctx_index]?為什么這么?。靠梢韵瓤聪耤md->conf如何定義的
struct ngx_command_s {
ngx_str_t name;
ngx_uint_t type;
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_uint_t conf;
ngx_uint_t offset;
void *post;
};
取值如下圖

該宏定義如下,是找到成員變量在結(jié)構(gòu)體中的偏移,也就可以根據(jù)cmd.conf找到是配置結(jié)構(gòu)體在ngx_http_conf_ctx_t結(jié)構(gòu)體中的哪個數(shù)組(main_conf、ser_conf、loc_conf),然后再根據(jù)模塊的ctx_index找到其對應(yīng)的配置結(jié)構(gòu)體
#define NGX_HTTP_MAIN_CONF_OFFSET offsetof(ngx_http_conf_ctx_t, main_conf) #define NGX_HTTP_SRV_CONF_OFFSET offsetof(ngx_http_conf_ctx_t, srv_conf) #define NGX_HTTP_LOC_CONF_OFFSET offsetof(ngx_http_conf_ctx_t, loc_conf)
4.2 遇到server塊怎么處理?
函數(shù)就不展開了,是ngx_http_core_module模塊的ngx_http_core_server,讀者可以自己去讀源碼

過程與遇到http塊差不多
- 創(chuàng)建一個ngx_http_conf_ctx_t結(jié)構(gòu)體變量ctx
- 將其main_conf指向http塊的main_conf位置,如圖綠色線部分,為srv_conf 和loc_conf重新分配內(nèi)存,
- 獲取srv_conf 數(shù)組中索引ngx_http_core_module.ctx_index的結(jié)構(gòu)體,就是索引為0的結(jié)構(gòu)體,也是ngx_http_core_srv_conf_t結(jié)構(gòu)體,將其結(jié)構(gòu)體成員ctx指向一開始創(chuàng)建的ctx,下圖右邊部分的圖示
- 將獲取到的ngx_http_core_srv_conf_t結(jié)構(gòu)體放入ngx_http_core_main_conf_t結(jié)構(gòu)體,如圖坐標(biāo)紅色箭頭的圖示,這樣不管遇到多少個server塊都能將其信息保存,同時也能反向查找到
- 繼續(xù)解析文件,調(diào)用ngx_conf_parse
/* parse inside server{} */
pcf = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_SRV_CONF;
rv = ngx_conf_parse(cf, NULL);

4.3 遇到location塊怎么處理?
同樣會遇到塊location,和上面一樣,直接查看ngx_http_core_location函數(shù),此時的cf->ctx 為 解析server塊時創(chuàng)建的ngx_http_conf_ctx_t

過程與上面的處理差不多,
- 依然會創(chuàng)建ngx_http_conf_ctx_t結(jié)構(gòu)體變量ctx
- 其main_conf與server_conf指向上一級,也就是處理server塊時創(chuàng)建的ngx_http_conf_ctx_t的結(jié)構(gòu)體main_conf與server_conf,而location則新分配內(nèi)存
這里有個不同,就是多個location塊怎么處理?
看下面代碼,注意ctx代碼為處理當(dāng)前l(fā)ocation生成的ngx_http_conf_ctx_t,而pctx為上一級也就是server塊生成的ngx_http_conf_ctx_t
ngx_http_core_loc_conf_t *clcf, *pclcf;
clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
clcf->loc_conf = ctx->loc_conf;
pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
在看ngx_http_add_location,這就不展開了,目的是將當(dāng)前l(fā)ocation的配置結(jié)構(gòu)體ngx_http_core_loc_conf_t 放入上一級的locations中取,如下圖:

結(jié)構(gòu)體分配完成后會繼續(xù)ngx_conf_parse,此時不會在遇到塊了,所以會將配置信息放入特殊的結(jié)構(gòu)體中,然后再一一退出遞歸(因?yàn)榇藭rngx_conf_parse還是在遞歸中)。
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
深入解析nginx-proxy/acme-companion高級部署方案
nginx-proxy/acme-companion項目提供了一種優(yōu)雅的解決方案,能夠自動為Docker容器管理的服務(wù)提供HTTPS支持,本文將重點(diǎn)介紹該項目的高級部署模式,幫助開發(fā)者構(gòu)建更安全、更靈活的容器化Web服務(wù)環(huán)境,感興趣的可以了解一下2026-05-05
Nginx訪問靜態(tài)資源配置的實(shí)現(xiàn)步驟
Nginx 擅長于底層服務(wù)器端資源的處理,例如靜態(tài)資源處理轉(zhuǎn)發(fā)、反向代理,負(fù)載均衡等,本文主要介紹了Nginx訪問靜態(tài)資源配置的實(shí)現(xiàn)步驟,具有一定的參考價值,感興趣的可以了解一下2023-09-09
nginx實(shí)現(xiàn)靜態(tài)文件的token認(rèn)證過程
這篇文章主要介紹了nginx實(shí)現(xiàn)靜態(tài)文件的token認(rèn)證過程,2024-06-06
Nginx負(fù)載均衡之upstream模塊簡介與使用詳解
nginx有一個最大的功能就是可以實(shí)現(xiàn)服務(wù)器的負(fù)載均衡,下面這篇文章主要給大家介紹了關(guān)于Nginx負(fù)載均衡之upstream模塊簡介與使用的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09
Windows系統(tǒng)下安裝及部署Nginx詳細(xì)教程(含多個站點(diǎn)部署)
Nginx是一個很強(qiáng)大的高性能Web和反向代理服務(wù),也是一種輕量級的Web服務(wù)器,可以作為獨(dú)立的服務(wù)器部署網(wǎng)站,應(yīng)用非常廣泛,這篇文章主要給大家介紹了關(guān)于Windows系統(tǒng)下安裝及部署Nginx(含多個站點(diǎn)部署)的相關(guān)資料,需要的朋友可以參考下2024-01-01

