# 17.2 Nginx Web 服务器

在高并发场景下，Web 服务器的性能与资源利用率成为系统架构设计的关键考量因素，直接影响着服务的可扩展性和响应性能。

Nginx（发音为“engine X”）是一个采用事件驱动异步架构的高性能 Web 服务器和反向代理服务器，其设计理念聚焦于高并发连接处理能力和低资源消耗，通过多进程单线程的工作模式实现了卓越的性能表现。

Nginx 以其事件驱动的异步架构和低内存占用特性，在大规模 Web 服务部署中得到广泛应用，其设计理念特别适合处理数以万计的并发连接。本章将介绍在 FreeBSD 平台上部署和配置 Nginx Web 服务器的完整流程。

## 安装 Nginx

在 FreeBSD 上可以通过 pkg 或 Ports 两种方式安装 Nginx。

使用 pkg 包管理器安装 Nginx 是最快捷的方式，能够自动处理依赖关系，执行以下命令即可完成安装。

```sh
# pkg install nginx
```

使用 Ports 方式安装 Nginx，这种方式提供了更大的配置灵活性，允许用户在编译前进行定制化设置，需要先进入对应的 Ports 目录，然后执行编译安装命令。

```sh
# cd /usr/ports/www/nginx/ 
# make install clean
```

### 查找相关的软件包

除了主程序外，系统还提供了多个与 Nginx 相关的软件包，可以通过以下方式进行检索，这些软件包涵盖了各种模块和扩展功能。

使用 pkg 命令可以快速检索与 Nginx 相关的软件包，这是一种高效的包管理方式。

```sh
$ pkg search -o nginx
```

在 Ports 目录中也可以查找与 Nginx 相关的软件包，这种方式适合需要查看源码的场景：

```sh
$ ls /usr/ports/www/ | grep nginx
```

## 守护进程

为了确保 Nginx 在系统启动时自动运行，保证服务的连续性和可靠性，需要先将其配置为开机自启服务，然后再手动启动服务进行测试。

设置 Nginx 服务在系统启动时自动启动：

```sh
# service nginx enable
nginx enabled in /etc/rc.conf
```

启动 Nginx 服务，在启动前系统会自动进行配置文件的语法检查：

```sh
# service nginx start
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Starting nginx.
```

可以通过以下命令查看 Nginx 正在监听的 IPv4 网络连接及端口，这是验证服务运行状态的有效方法：

```sh
# sockstat -4 | grep nginx
www      nginx       1154 6   tcp4   *:80                  *:*
root     nginx       1153 6   tcp4   *:80                  *:*
```

## 浏览网页

确认 Nginx 服务正常运行后，可以通过浏览器访问来验证 Web 服务器是否工作正常，这是部署过程中的重要验证步骤。

在本机浏览器中打开 `localhost`，或使用服务器 IP 地址访问，例如 `http://192.168.179.150/`：

![NGINX FreeBSD](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-415fd6db447be03c144dcec4636ac6cebb49b791%2Fnginx1.png?alt=media)

## 配置文件

Nginx 功能强大且配置灵活，其配置采用模块化的结构设计，详细的配置方法请参阅官方文档。本文仅简要说明在 FreeBSD 中如何启动 Nginx 及其配置文件位置和使用方法。

有关配置教程，请参阅 [官方文档](https://nginx.org/en/docs/)，官方文档提供了最权威和完整的配置说明。

在 FreeBSD 中，Nginx 的配置文件位于 `/usr/local/etc/nginx/` 目录下，主要配置文件为 `/usr/local/etc/nginx/nginx.conf`，该文件采用层次化的结构组织。

目录结构：

```sh
/usr/local/
├── etc/
│   └── nginx/
│       ├── nginx.conf          # Nginx 主配置文件
│       └── mime.types          # MIME 类型定义文件
└── www/
    └── nginx/                  # Nginx 站点根目录
```

默认配置中，Nginx 的站点根目录为 `/usr/local/www/nginx/`。如需更改站点根目录，请在 `/usr/local/etc/nginx/nginx.conf` 中将

```nginx
root	/usr/local/www/nginx;
```

修改为你希望的目录路径，例如 `root /path/to/new/webroot;`，配置修改后需要重启服务才能生效。

### 示例配置文件（Nginx + Typecho 伪静态 + SSL）

为了帮助读者更好地理解 Nginx 的配置，下面提供一个完整的示例配置文件，包含 Nginx、Typecho 伪静态规则以及 SSL 配置，这个示例展示了 Nginx 在实际生产环境中的典型应用场景。

```nginx
#user  nobody;                                   # 指定 Nginx 运行用户，默认注释表示使用编译时设置
worker_processes  1;                             # 工作进程数量

# This default error log path is compiled-in      # 说明默认错误日志路径的编译行为
# to make sure configuration parsing             # 确保配置解析错误有日志记录
# errors are logged somewhere, especially        # 尤其是在无人值守启动时
# during unattended boot when stderr             # 标准错误通常不会被记录
# isn't normally logged anywhere. This path      # 该路径在每次启动时都会被触碰
# will be touched on every nginx                 # 无论是否配置其他错误日志路径
# start regardless of error log location         # 详细信息参考下方链接
# configured here. See
# https://trac.nginx.org/nginx/ticket/147         # 官方问题跟踪链接
# for more info.
#
#error_log  /var/log/nginx/error.log;             # 错误日志文件路径
#

#pid        logs/nginx.pid;                       # Nginx 主进程 PID 文件路径


events {                                         # events 模块配置开始
    worker_connections  1024;                    # 单个工作进程允许的最大连接数
}                                                # events 模块结束


http {                                           # http 模块配置开始
    include       mime.types;                    # 引入 MIME 类型定义文件
    default_type  application/octet-stream;     # 默认响应的 MIME 类型

    #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  logs/access.log  main;           # 访问日志路径及使用的格式

    sendfile        on;                          # 启用 sendfile 以提高文件传输效率
    #tcp_nopush     on;                          # 配合 sendfile 使用，减少网络包

    #keepalive_timeout  0;                       # 禁用 keepalive
    keepalive_timeout  65;                       # keepalive 超时时间（秒）

    #gzip  on;                                  # 启用 gzip 压缩


    server {                                     # HTTP 虚拟主机配置开始
        listen       80;                         # 监听 80 端口
        server_name  localhost;                  # 虚拟主机名

        #charset koi8-r;                         # 设置字符集

        #access_log  logs/host.access.log  main; # 虚拟主机访问日志

        location / {                             # 根路径匹配规则
            root   /usr/local/www/nginx;         # 网站根目录
            index  index.html index.htm index.php; # 默认首页文件顺序

            if (-f $request_filename/index.html){# 判断是否存在 index.html
                rewrite (.*) $1/index.html break;# 重写到 index.html
            }
            if (-f $request_filename/index.php){ # 判断是否存在 index.php
                rewrite (.*) $1/index.php;       # 重写到根目录下的 index.php
            }
            if (!-f $request_filename){          # 判断请求文件是否不存在
                rewrite (.*) /index.php;         # 重写到根目录 index.php
            }
        }                                        # location / 结束


        location ~ .*.php(/.*)*$ {               # 匹配 PHP 请求
            root           /usr/local/www/nginx; # PHP 文件根目录
            fastcgi_pass   127.0.0.1:9000;       # FastCGI 服务地址
            fastcgi_index  index.php;            # 默认 FastCGI 索引文件
            fastcgi_param  SCRIPT_FILENAME $request_filename; # PHP 脚本路径
            include        fastcgi_params;       # 引入 FastCGI 参数文件
        }                                        # PHP location 结束


        #error_page  404              /404.html; # 自定义 404 页面

        error_page   500 502 503 504  /50x.html; # 定义 5xx 错误页面
        location = /50x.html {                   # 精确匹配 50x.html
            root   /usr/local/www/nginx-dist;    # 错误页面目录
        }                                        # 错误页面 location 结束

        #location ~ /.ht {                       # 匹配 .ht* 文件
        #    deny  all;                          # 拒绝访问
        #}
    }                                            # HTTP server 结束


    server {                                     # HTTPS 虚拟主机配置开始
        listen       443 ssl;                        # 监听 443 端口
        server_name  localhost;                  # 虚拟主机名

        ssl_certificate      /usr/local/etc/nginx/fbxs.crt; # SSL 证书路径
        ssl_certificate_key  /usr/local/etc/nginx/fbxs.key; # SSL 私钥路径
        ssl_session_timeout 5m;                  # SSL 会话超时时间
        ssl_protocols TLSv1.2 TLSv1.3;     # 配置启用的 TLS 协议版本（可根据安全要求调整）
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; # 加密套件
        ssl_prefer_server_ciphers on;            # 优先使用服务器端加密套件

        location ~ .*.php(/.*)*$ {               # HTTPS 下 PHP 请求处理
            root           /usr/local/www/nginx-dist; # HTTPS 网站根目录
            fastcgi_pass   127.0.0.1:9000;       # FastCGI 服务地址
            fastcgi_index  index.php;            # 默认 FastCGI 索引文件
            fastcgi_param  SCRIPT_FILENAME $request_filename; # PHP 脚本路径
            include        fastcgi_params;       # 引入 FastCGI 参数
        }                                        # HTTPS PHP location 结束

        location / {                             # HTTPS 根路径匹配
            root   /usr/local/www/nginx-dist;    # HTTPS 网站根目录
            index  index.php;                    # 默认首页文件
        }                                        # HTTPS location / 结束
    }                                            # HTTPS server 结束

}                                                # HTTP 模块结束
```

## 课后习题

1. 为 FreeBSD Port www/nginx 新增目前缺失的 make 选项。
2. 在 FreeBSD 中，基于 www/nginx 配置 HTTPS 支持，实现自动签名。
3. 在 FreeBSD 中，基于 www/nginx 部署一个论坛（如使用 Discuz!）。
