基于 LNMP架构 搭建 Discuz 社区论坛Web应用
一、搭建 Nginx 服务
1. 解压源码包
[root@localhost opt]#
tar -xf nginx-1.22.0.tar.gz
2. 安装 Nginx 环境依赖包
[root@localhost opt]#
yum -y install \
pcre-devel \
zlib-devel \
gcc \
gcc-c++ \
make \
openssl \
openssl-devel
- pcre-devel:PCRE 是一个正则表达式库,pcre-devel 包是开发 PCRE 应用程序所需的头文件和库文件。
- zlib-devel:Zlib 是一个数据压缩库,zlib-devel 包提供了用于开发 Zlib 应用程序的头文件和库文件。
- gcc 和 gcc-c++:C/C++ 编译器,用于编译源代码。
- make:构建工具,用于自动化编译过程。
- openssl 和 openssl-devel:OpenSSL 是一个加密库,openssl-devel 包是用于开发 OpenSSL 应用程序所需的头文件和库文件。
3. 创建管理用户
[root@localhost opt]#
useradd -M -s /sbin/nologin nginx
4. 设置安装路径及模块
cd nginx-1.22.0/
[root@localhost nginx-1.22.0]#
./configure \
--prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-http_stub_status_module \
--with-http_ssl_module
5. 编译与安装
[root@localhost nginx-1.22.0]#
make -j 4 && make install
6. 优化 Nginx 命令
[root@localhost nginx-1.22.0]#
ln -s /usr/local/nginx/sbin/nginx /usr/local/bin/
7. 添加 Nginx 系统服务
[root@localhost nginx-1.22.0]#
vim /lib/systemd/system/nginx.service
[Unit]
Description=nginx
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx
ExecStop=/bin/kill -s QUIT $MAINPID
ExecReload=/bin/kill -s HUP $MAINPID
PrivateTmp=True
[lnstall]
WantedBy=multi-user.target
:wq!
# 添加执行权限
chmod 754 /lib/systemd/system/nginx.service
配置文件每行含义
-
[Unit]
:表示此部分包含了关于服务单元的基本元数据和依赖关系。-
Description=nginx
:设置服务名称为nginx
。 -
After=network.target
:指定此服务需要在network.target
启动后才能启动,因为nginx
服务需要网络支持。
-
-
[Service]
:表示此部分包含有关如何启动和停止服务的信息。-
Type=forking
:表示此服务以 fork 方式启动,在后台运行,且需要使用 PID 文件进行管理。 -
PIDFile=/usr/local/nginx/logs/nginx.pid
:指定服务 PID 的位置,即/usr/local/nginx/logs/nginx.pid
。 -
ExecStart=/usr/local/nginx/sbin/nginx
:定义服务启动时执行的命令,即启动/usr/local/nginx/sbin/nginx
程序。 -
ExecReload=/bin/kill -s HUP $MAINPID
:定义重新加载服务配置的命令,即使用指定信号HUP
重新读取配置文件。其中$MAINPID
为环境变量,表示主进程的 PID。 -
ExecStop=/bin/kill -s QUIT $MAINPID
:定义停止服务的命令,即使用指定信号QUIT
平稳退出服务。 -
PrivateTmp=true
:表示此服务使用私有临时目录。在 systemd 中,
PrivateTmp=true
的意思是为该服务分配一个私有的、独立的 tmp(临时文件)目录。这个 tmp 目录与系统的 tmp 目录是分离开的,只能被该服务本身及其子进程使用,其他进程无法访问。使用私有临时目录可以提高服务的安全性,因为它可以避免对系统的 tmp 目录产生影响,减少出现文件冲突的可能性。同时,私有临时目录可以清楚地记录该服务所创建的所有 tmp 文件和临时目录,便于管理和清理。
此外,私有临时目录还可以更好地保护系统的隐私信息,避免敏感数据被泄露。在多租户场景下,使用私有临时目录还可以避免不同用户之间共享 tmp 目录带来的潜在风险。
因此,在实际部署中,对于一些需要使用 tmp 目录的服务,建议设置
PrivateTmp=true
,以提高系统的安全性和可靠性。
-
-
[Install]
:表示此部分包含了如何安装服务单元的信息。WantedBy=multi-user.target
:指定此服务应该被连接到哪个系统级别目标,即multi-user.target
,使得在多用户模式下启动时自动启动nginx
服务。
8.启动 Nginx 服务
[root@localhost nginx-1.22.0]#
nginx
9. 访问 Nginx 服务器
注:如果Nginx服务成功开启,但浏览器无法访问,有可能是防火墙的问题。
二、搭建 MySQL 数据库
1. 解压 MySQL 源码包
[root@localhost opt]#
tar -xf mysql-boost-5.7.20.tar.gz
2. 安装 MySQL 环境依赖包
yum -y install \
ncurses \
ncurses-devel \
bison \
cmake
ncurses
:是一个 C 库,用于屏幕输出和字符输入,为编写命令行界面程序提供支持。ncurses-devel
:是 ncurses 库的开发库,包含了与 ncurses 相关的头文件和库文件,用于开发需要依赖 ncurses 库的程序。bison
:是一个语法分析器生成器,可根据一组规则生成 LALR(1) 类型的语法分析器。在编译 MySQL 时需要使用 bison 来生成编译器。cmake
:是一个开源的构建自动化工具,可以帮助开发者编写跨平台的 C/C++ 项目。在编译 MySQL 时需要使用 cmake 来生成 Makefile 文件。
3. 创建 MySQL 的运行用户
useradd -M -s /sbin/nologin mysql
4. 编译安装 MySQL 数据库
(1)设置安装路径及模块
cd /opt/mysql-5.7.20/
[root@localhost mysql-5.7.20]#
cmake \
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \
-DMYSQL_UNIX_ADDR=/usr/local/mysql/mysql.sock \
-DSYSCONFDIR=/etc \
-DSYSTEMD_PID_DIR=/usr/local/mysql \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DWITH_EXTRA_CHARSETS=all \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_ARCHIVE_STORAGE_ENGINE=1 \
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
-DWITH_PERFSCHEMA_STORAGE_ENGINE=1 \
-DMYSQL_DATADIR=/usr/local/mysql/data \
-DWITH_BOOST=boost \
-DWITH_SYSTEMD=1
(2)编译与安装
[root@localhost mysql-5.7.20]#
make -j 6 && make install
5、修改 MySQL 配置文件
vim /etc/my.cnf
[client]
port = 3306
socket=/usr/local/mysql/mysql.sock
[mysqld]
user = mysql
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
port = 3306
character-set-server=utf8
pid-file = /usr/local/mysql/mysqld.pid
socket=/usr/local/mysql/mysql.sock
bind-address = 0.0.0.0
skip-name-resolve
max_connections=2048
default-storage-engine=INNODB
max_allowed_packet=16M
server-id = 1
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,PIPES_AS_CONCAT,ANSI_QUOTES
[client]
:标识客户端相关的配置port = 3306
:指定MySQL服务器的端口号,通常为3306socket=/usr/local/mysql/mysql.sock
:指定连接MySQL服务器的socket文件路径[mysqld]
:标识MySQL服务器相关的配置user = mysql
:MySQL服务器运行的用户basedir=/usr/local/mysql
:MySQL安装目录datadir=/usr/local/mysql/data
:MySQL数据目录port = 3306
:MySQL服务器监听的端口号character-set-server=utf8
:指定数据库默认字符集为utf8pid-file = /usr/local/mysql/mysqld.pid
:指定MySQL服务器进程ID文件路径socket=/usr/local/mysql/mysql.sock
:指定MySQL服务器监听的socket文件路径bind-address = 0.0.0.0
:指定MySQL服务器监听的IP地址,默认为所有IP地址skip-name-resolve
:禁止通过域名解析进行授权max_connections=2048
:指定MySQL服务器允许的最大连接数为2048个default-storage-engine=INNODB
:MySQL服务器默认的存储引擎为InnoDBmax_allowed_packet=16M
:MySQL服务器接收数据包的最大大小为16Mserver-id = 1
:MySQL服务器的唯一ID,用于复制和主从同步sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,PIPES_AS_CONCAT,ANSI_QUOTES
:MySQL服务器运行时的SQL模式设置,包括了多个配置项。
6. 更改文件属主 属组
[root@localhost ~]#
chown mysql:mysql /etc/my.cnf
chown -R mysql:mysql /usr/local/mysql/
7. 配置全局环境变量
[root@localhost mysql-5.7.20]#
echo 'export PATH=/usr/local/mysql/bin:/usr/local/mysql/lib:$PATH' >> /etc/profile
source /etc/profile
8. 初始化数据库
cd /usr/local/mysql/bin/
./mysqld \
--initialize-insecure \
--user=mysql \
--basedir=/usr/local/mysql \
--datadir=/usr/local/mysql/data
9. 添加系统服务
[root@localhost bin]#
cp /usr/local/mysql/usr/lib/systemd/system/mysqld.service /usr/lib/systemd/system
10. 重新加载配置文件与启动
[root@localhost bin]#
systemctl daemon-reload
systemctl start mysqld.service
systemctl enable mysqld.service
11. 修改 MySQL 的登录密码
mysql -u root
alter user 'root'@'localhost' identified by '123123';
\q
12. root 登录 MySQL
mysql -u root -p
三、安装配置 PHP 解析环境
1. 解压 PHP 源码包
[root@localhost opt]#
tar -xf php-7.1.10.tar.bz2
2. 安装 PHP 依赖包
yum -y install gd \
libjpeg libjpeg-devel \
libpng libpng-devel \
freetype freetype-devel \
libxml2 libxml2-devel \
zlib zlib-devel \
curl curl-devel \
openssl openssl-devel
- gd:程序中常用的一个处理图像的库。
- libjpeg 和 libjpeg-devel:JPEG 图像格式编解码库和相关的开发工具。
- libpng 和 libpng-devel:PNG 图像格式编解码库和相关的开发工具。
- freetype 和 freetype-devel:TrueType 字体渲染库和相关的开发工具。
- libxml2 和 libxml2-devel:XML 解析库和相关的开发工具。
- zlib 和 zlib-devel:压缩算法库和相关的开发工具。
- curl 和 curl-devel:网络传输库和相关的开发工具。
- openssl 和 openssl-devel:加密库和相关的开发工具。
3. 设置安装路径及模块
cd php-7.1.10
[root@localhost php-7.1.10]#
./configure \
--prefix=/usr/local/php \
--with-mysql-sock=/usr/local/mysql/mysql.sock \
--with-mysqli \
--with-zlib \
--with-curl \
--with-gd \
--with-jpeg-dir \
--with-png-dir \
--with-freetype-dir \
--with-openssl \
--enable-fpm \
--enable-mbstring \
--enable-xml \
--enable-session \
--enable-ftp \
--enable-pdo \
--enable-tokenizer \
--enable-zip
./configure \
:运行 ./configure 脚本,用于自动配置PHP的编译选项。--prefix=/usr/local/php \
:指定PHP的安装目录为 /usr/local/php。--with-mysql-sock=/usr/local/mysql/mysql.sock \
:指定MySQL的socket路径。--with-mysqli \
:启用MySQLi扩展以支持MySQL数据库。--with-zlib \
:启用zlib扩展以支持数据压缩和解压。--with-curl \
:启用cURL扩展以支持各种网络协议。--with-gd \
:启用GD库以支持图像处理。--with-jpeg-dir \
:指定JPEG库的路径。--with-png-dir \
:指定PNG库的路径。--with-freetype-dir \
:指定FreeType库的路径。--with-openssl \
:启用OpenSSL扩展以支持安全通信协议。--enable-fpm \
:启用FastCGI Process Manager(FPM)以提高PHP的性能和稳定性。--enable-mbstring \
:启用多字节字符串扩展以支持多语言字符集。--enable-xml \
:启用XML扩展以支持XML数据处理。--enable-session \
:启用会话扩展以支持会话管理。--enable-ftp \
:启用FTP扩展以支持FTP协议。--enable-pdo \
:启用PDO扩展以支持不同类型的数据库。--enable-tokenizer \
:启用Tokenizer扩展以支持代码解析。--enable-zip
:启用Zip扩展以支持压缩和解压缩文件。
4. 编译与安装
[root@localhost php-7.1.10]#
make -j 6 && make install
5. 优化 PHP 命令
ln -s /usr/local/php/bin/* /usr/local/bin/
ln -s /usr/local/php/sbin/* /usr/local/sbin/
6. 调整 PHP 配置文件
php.ini
:主配置文件。所有的 PHP 配置选项都可以在这个文件中找到。这个文件包含了一些全局配置,比如内存限制、上传文件大小限制、错误报告级别、时区设置等。PHP 运行时会优先读取这个文件来进行一些全局性的配置。php-fpm.conf
:进程服务配置文件。这个文件包含了 PHP-FPM 的配置选项,通常用于配置 PHP 的进程管理器,比如启动的进程数、监听的套接字地址等。PHP-FPM 是一个可以为 PHP 提供 FastCGI 协议支持的进程管理器,允许将 PHP 程序作为一个独立的服务运行,并提供了进程池、请求过滤、错误处理等功能。www.conf
:扩展配置文件。这个文件包含了 PHP-FPM 扩展的相关配置选项。比如用户和组设置、运行模式、监听的套接字地址等。通常会指定 PHP-FPM 进程池中每个工作进程的属性,并为每个网站或者应用程序单独配置一个 PHP-FPM 进程池。
这三个配置文件各司其职,主配置文件用于配置整个 PHP 运行环境,进程服务配置文件用于配置 PHP 的进程管理器,而扩展配置文件则用于为每个网站或应用程序配置不同的 PHP 进程池,并控制 PHP-FPM 进程中各个工作进程的属性
(1)php.ini 主文件
cp /opt/php-7.1.10/php.ini-development /usr/local/php/lib/php.ini
vim /usr/local/php/lib/php.ini
# 修改939行,去掉注释 ; 分号,指定时区
data.timezone = Asia/Shanghai
# 修改1170行,指定mysql的套接字文件路径
mysqli.default_socket = /usr/local/mysql/mysql.sock
:wq!
# 验证安装的模块
php -m
(2)php-fpm.conf 进程服务配置文件
cp /opt/php-7.1.10/php.ini-development /usr/local/php/lib/php.ini
vim /usr/local/php/lib/php.ini
# 去掉第17行的注释 ; 号,配置php-fpm的pid号
pid = run/php-fpm.pid
:wq!
(3)www.conf 文件
cp /usr/local/php/etc/php-fpm.d/www.conf.default /usr/local/php/etc/php-fpm.d/www.conf
7. 启动 php-fpm
/usr/local/php/sbin/php-fpm -c /usr/local/php/lib/php.ini
8. 添加系统服务
cp /opt/php-7.1.10/sapi/fpm/php-fpm.service /lib/systemd/system/php-fpm.service
systemctl restart php-fpm.service
9. 配置 Nginx 支持 PHP 解析
vim /usr/local/nginx/conf/nginx.conf
# 在45行添加 php 文件
index index.html index.htm index.php;
# 第65-71行注释取消,69行的 /secripts 换成 nginx 的工作目录
location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /usr/local/nginx/html$fastcgi_script_name;
include fastcgi_params;
}
:wq!
systemctl restart nginx.service
10. 验证 PHP 测试页
vim /usr/local/nginx/html/index.php
<?php
phpinfo();
?>
:wq!
调用了一个名为 phpinfo()
的函数。该函数的作用是输出当前 PHP 环境的详细信息,包括 PHP 版本、编译选项、已加载的模块等等
浏览器访问服务器
http://192.168.23.5/index.php
11. 验证数据库是否正常工作
(1)创建数据库
mysql -u root -p
123123
create database bbs;
grant all on bbs.* to 'bbsuser'@'%' identified by 'admin123'
grant all on bbs.* to 'bbsuser'@'localhost' identified by 'admin123'
flush privileges;
\q
- 第一行命令
mysql -u root -p
表示使用root
用户登录 MySQL 数据库。输入密码后即可进入 MySQL 控制台。 - 第二行命令
create database bbs;
表示在当前 MySQL 环境下创建一个名为bbs
的数据库。 - 第三行命令
grant all on bbs.* to 'bbsuser'@'%' identified by 'admin123'
表示为名为bbsuser
的用户授权对bbs
数据库进行所有操作,并且该用户可以从任意 IP 地址访问该数据库。另外,该用户的密码为admin123
。 - 第四行命令
grant all on bbs.* to 'bbsuser'@'localhost' identified by 'admin123'
表示为名为bbsuser
的用户授权对bbs
数据库进行所有操作,并且该用户可以从本地主机(即使用localhost
访问时)访问该数据库。与上一行命令不同的是,在此处通过使用identified by
子句指定了用户密码。 - 第五行命令
flush privileges;
用于刷新 MySQL 权限缓存,以使新的权限设置立即生效。 - 最后一行
\q
表示退出mysql界面
需要注意的是,为了保证 MySQL 数据库的安全性,应该尽量避免使用 root
用户进行一般性操作,而应该创建新的用户并分配适当的权限。此外,对于授权语句,需要根据实际需求进行细化和限制,以防止意外操作或滥用权限产生的风险。
(2)编写 PHP 测试页
vim /usr/local/nginx/html/index.php
<?php
$link=mysqli_connect('192.168.23.5','bbsuser','admin123');
if($link)
echo "<h1>Success!!</h1>";
else
echo "Fail!!";
?>
浏览器访问服务器
http://192.168.23.5/index.php
四、搭建部署 Discuz 社区论坛 Web应用
1. 解压 Discuz 源码包
cd /opt
unzip Discuz_X3.4_SC_UTF8.zip -d /opt/dis
2. 将 Discuz 论坛 部署到 Nginx
cp -r /opt/dis/dir_SC_UTF8/upload/ /usr/local/nginx/html/bbs/
cd /usr/local/nginx/html/bbs/
chmod -R 777 config/
chmod -R 777 data/
chmod -R 777 uc_client/
chmod -R 777 uc_server/
浏览器访问论坛页面
http://192.168.23.5/bbs/install/index.php
五、设置控制访问 Nginx 页面
(一)访问状态统计配置
HTTP_STUB_STATUS
是一个Nginx的内置变量,它用于获取当前服务器的状态信息。当开启了Nginx的stub_status模块,并在配置中设置了stub_status on;
时,可以通过访问特定的URL路径来获取服务器的状态信息。
对于HTTP_STUB_STATUS
这个内置变量,它会返回一个包含服务器状态信息的响应。例如,通过访问http://example.com/status
路径,可以获取如下类似的响应:
复制代码Active connections: 10
server accepts handled requests
1000 1000 10000
Reading: 1 Writing: 2 Waiting: 7
这些信息包括:
Active connections
:当前活动连接数。server accepts handled requests
:服务器启动以来接收、处理和完成的请求计数。Reading
,Writing
,Waiting
:当前正在读取请求、正在写入响应和等待的连接数。
通过解析这些状态信息,你可以获得关于Nginx服务器的实时性能指标,如并发连接数、请求处理情况等,用于监控和调试服务器。
1. 查看Nginx是否安装HTTP_STUB_STATUS 模块
/usr/local/nginx/sbin/nginx -V
2. 指定文件位置并添加stub_status配置
vim /usr/local/nginx/conf/nginx.conf
location status {
stub_status on;
access_log off;
}
:wq!
# 重启服务
systemctl restart nginx.service
3. 浏览器访问
http://192.168.23.5/status
(二)基于授权的访问控制
1. 下载 http-tools 工具并设置用户及密码
# 生成用户密码文件
yum -y install httpd-tools
htpasswd -c /usr/local/nginx/passwd.db zhuangsan
123123
123123
# 修改主配置文件相对应目录,添加认证配置项
vim /usr/local/nginx/conf/nginx.conf
location / {
root html;
index index.html index.htm index.php;
auth_basic secret;
auth_basic_user_file /usr/local/nginx/passwd.db;
}
:wq!
# 检查配置文件是否有错
nginx -t
# 重启Nginx服务
systemctl restart nginx
- 第43行:
location
关键字用于定义一个URL路径的匹配规则。在这个例子中,location
块没有指定具体的URL路径,因此会匹配所有请求。 - 第47行:
auth_basic
用于开启基本身份验证,并设置验证的提示信息。secret
是验证提示信息的内容,可以自定义为你想要显示给用户的内容。 - 第58行:
auth_basic_user_file
指定了存储用户名和密码的文件路径。/usr/local/nginx/passwd.db
是包含用户名和密码的文件,通常使用.htpasswd
格式或其他支持的格式。
通过上述配置,当用户访问该Nginx服务器时,如果请求匹配了这个location
块,将触发基本身份验证。服务器会要求用户提供用户名和密码,然后通过验证文件(/usr/local/nginx/passwd.db
)来验证用户的凭据。
请确保验证文件的路径和格式正确,并根据需要调整配置中的路径和提示信息。同时,还需要确保Nginx已经安装并启用了HTTP Auth Basic模块,否则基本身份验证将无法生效。
2. 浏览器访问
http://192.168.23.5/
(三)基于客户端的访问控制
1. 设置规则
访问控制规则如下:
deny IPIP 段:拒绝某个 IP 或 IP 段的客户端访问。
allow IPIP 段:允许某个 IP 或 IP 段的客户端访问。
规则从上往下执行,如匹配则停止,不再往下匹配。
vim /usr/local/nginx/conf/nginx.conf
location / {
root html;
index index.html index.htm index.php;
deny 192.168.23.5;
allow all;
}
# 重启 Nginx 服务
systemctl restart nginx
2. 浏览器访问
(四)基于域名的 Nginx 虚拟机主机
1. 提供虚拟机域名解析
echo "192.168.23.5 www.host1.com" >> /etc/hosts
2. 设置域名
vim /usr/local/nginx/conf/nginx.conf
server {
listen 80;
server_name www.host1.com;
charset utf-8;
location / {
root /usr/local/nginx/html/host1;
index index.html;
}
error_page 500 502 503 504 /50x.html;
location = 50x.html{
root html;
}
}
:wq!
# 重启 Nginx 服务
systemctl restart nginx
3. 浏览器访问
http://www.host1.com
(五)基于IP的 Nginx 虚拟主机
1. 创建虚拟网卡
ifconfig ens33:0 192.168.23.6 netmask 255.255.255.0
ifconfig ens33:0 up
2. 设置监听地址
vim /usr/local/nginx/conf/nginx.conf
server {
listen 192.168.23.5:80;
server_name www.host1.com;
charset utf-8;
location / {
root /usr/local/nginx/html/host1;
index index.html;
}
error_page 500 502 503 504 /50x.html;
location = 50x.html{
root html;
}
}
server {
listen 192.168.23.6:80;
server_name www.host2.com;
charset utf-8;
location / {
root /usr/local/nginx/html/host2;
index index.html;
}
error_page 500 502 503 504 /50x.html;
location = 50x.html{
root html;
}
}
# 重启 Nginx 服务
systemctl restart nginx
3. 浏览器访问
(六)基于端口的 Nginx 虚拟主机
1. 设置监听端口
vim /usr/local/nginx/conf/nginx.conf
server {
listen 192.168.23.5:8080;
server_name www.host1.com;
charset utf-8;
location / {
root /usr/local/nginx/html/host1;
index index.html;
}
error_page 500 502 503 504 /50x.html;
location = 50x.html{
root html;
}
}
server {
listen 192.168.23.5:8888;
server_name www.host2.com;
charset utf-8;
location / {
root /usr/local/nginx/html/host2;
index index.html;
}
error_page 500 502 503 504 /50x.html;
location = 50x.html{
root html;
}
}
# 重启 Nginx 服务
systemctl restart nginx