玩转NAS | 打造一个动态网关,部署OpenResty - Nginx与Lua的强强联合

0x00 前言简述

最近一个项目中用到 Openresty,作者使用后感觉其比 Nginx 更加强大,结合Lua脚本语言可以做更多的有趣的事情,例如,结合 Redis 缓存数据库做一个实时访问统计以及链路追踪,于是就想着在性价比超高的QNAP 464C2 NAS中安装一个 Openresty 用于后续在NAS中反代一些服务用作于动态Web网关。

什么是 Openresty?

OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关, 简单的说:它是一个通过 Lua 扩展 NGINX 实现的可伸缩的 Web 平台。

例如,我们先来看一个简答的OpenResty的Hello World示例,创建一个名为conf/nginix.conf的简单纯文本文件,其中包含以下内容:

代码语言:javascript
复制
worker_processes  1;
error_log logs/error.log;
events {
    worker_connections 1024;
}
http {
    server {
        listen 8080;
        location / {
            default_type text/html;
            content_by_lua_block {
                ngx.say("<p>hello, world</p>")
            }
        }
    }
}

运行 OpenResty 后使用浏览器访问http://OpenRestyIP:8080/,将看到返回的hello, world文本内容,而不再是在Nginx中常常使用的return指令来返回响应数据。

为啥要用 Openresty?

OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。OpenResty® 的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。

<br./>

OpenResty & Nginx 有啥关系?

OpenResty 和 Nginx 之间有着紧密的关系。OpenResty 可以看做是基于 Nginx 的一个分支(PS: 实际上是一个独立的软件包),它将 LuaJIT 虚拟机嵌入到 Nginx 中,从而提供了一个强大的 Web 平台,使得开发者可以使用 Lua 脚本来扩展 Nginx 的功能。

以下是 OpenResty 和 Nginx 之间的一些关键联系和区别:

特性/方面

OpenResty

Nginx

基础

基于 Nginx 高性能 Web 服务器

高性能 Web 服务器

Lua 支持

集成 LuaJIT VM,支持 Lua 脚本

不直接支持 Lua,可通过第三方模块实现

第三方模块

包含额外的第三方 C 模块

可编译时添加第三方模块

版本

通常使用 Nginx 的 Mainline 版本

提供 Mainline、Stable 和 Legacy 版本

配置指令

增加了 Lua 相关的配置指令

标准 Nginx 配置指令

默认模块

默认包含四层负载均衡和 TLS 协议处理功能

可能需要手动配置这些功能

性能优化

使用 -O2 优化参数

使用 -O1 优化参数

社区和生态

活跃的社区,提供大量 Lua 模块和文档

广泛的用户基础和插件生态

使用场景

适合需要高性能和可扩展性的 Web 应用和微服务

适用于各种 Web 服务和反向代理场景

稳定性

可能包含最新的特性和改进,但可能相对不稳定

Stable 版本更稳定

总的来说,OpenResty 是 Nginx 的一个增强版,它通过集成 LuaJIT 和其他模块,提供了更多的功能和灵活性,特别适合需要高性能和可扩展性的 Web 应用和微服务架构。

参考来源

  • openresty 中文官网:http://openresty.org/cn/

0x01 部署实践

这里作者主要针对在NAS中进行搭建部署的 Openresty 应用,若需要在其他Linux发行版中进行源码编译安装或者是二进制安装的,可参考其快速上路稳定 http://openresty.org/cn/getting-started.html

Step 1.在QNAP NAS中部署 Openresty 主要有两种方式, 一种是通过 docker run 进行安装,另一种则是通过 docker-compose 安装。

代码语言:javascript
复制
# 创建持久化目录,包含 静态资源 www, 证书目录 cert, 以及配置文件目录 conf.d
mkdir -vp /share/Container/gateway-web/{www,cert,conf.d}

Nginx 基础配置文件

tee /share/Container/gateway-web/nginx.conf << EOF

nginx.conf -- docker-openresty

See https://github.com/openresty/docker-openresty/blob/master/README.md#nginx-config-files

#user nobody;
#worker_processes 1;

Enables the use of JIT for regular expressions to speed-up their processing.

pcre_jit on;

#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

#pid logs/nginx.pid;

events {
worker_connections 1024;
}

http {
include mime.types;
default_type application/octet-stream;

Enables or disables the use of underscores in client request header fields.

When the use of underscores is disabled, request header fields whose names contain underscores are marked as invalid and become subject to the ignore_invalid_headers directive.

underscores_in_headers off;

#log_format main 'remote_addr - remote_user [time_local] &#34;request" '

'status body_bytes_sent "$http_referer" '

'"http_user_agent&#34; &#34;http_x_forwarded_for"';

#access_log logs/access.log main;

  # Log in JSON Format
  # log_format nginxlog_json escape=json &#39;{ &#34;timestamp&#34;: &#34;$time_iso8601&#34;, &#39;
  # &#39;&#34;remote_addr&#34;: &#34;$remote_addr&#34;, &#39;
  #  &#39;&#34;body_bytes_sent&#34;: $body_bytes_sent, &#39;
  #  &#39;&#34;request_time&#34;: $request_time, &#39;
  #  &#39;&#34;response_status&#34;: $status, &#39;
  #  &#39;&#34;request&#34;: &#34;$request&#34;, &#39;
  #  &#39;&#34;request_method&#34;: &#34;$request_method&#34;, &#39;
  #  &#39;&#34;host&#34;: &#34;$host&#34;,&#39;
  #  &#39;&#34;upstream_addr&#34;: &#34;$upstream_addr&#34;,&#39;
  #  &#39;&#34;http_x_forwarded_for&#34;: &#34;$http_x_forwarded_for&#34;,&#39;
  #  &#39;&#34;http_referrer&#34;: &#34;$http_referer&#34;, &#39;
  #  &#39;&#34;http_user_agent&#34;: &#34;$http_user_agent&#34;, &#39;
  #  &#39;&#34;http_version&#34;: &#34;$server_protocol&#34;, &#39;
  #  &#39;&#34;nginx_access&#34;: true }&#39;;
  # access_log /dev/stdout nginxlog_json;

See Move default writable paths to a dedicated directory (#119)

Issue #119 · openresty/docker-openresty

client_body_temp_path /var/run/openresty/nginx-client-body;
proxy_temp_path /var/run/openresty/nginx-proxy;
fastcgi_temp_path /var/run/openresty/nginx-fastcgi;
uwsgi_temp_path /var/run/openresty/nginx-uwsgi;
scgi_temp_path /var/run/openresty/nginx-scgi;

sendfile on;
#tcp_nopush on;

#keepalive_timeout 0;
keepalive_timeout 65;

#gzip on;

include /etc/nginx/conf.d/*.conf;

Don't reveal OpenResty version to clients.

server_tokens off;

}
EOF

Step 2.在NAS中创建默认Server配置文件不带SSL配置,配置文件内容如下所示。

代码语言:javascript
复制
tee /share/Container/gateway-web/conf.d/default.conf <<'EOF'
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/local/openresty/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/openresty/nginx/html;
}
}
EOF

创建一个测试页面,用于验证部署成功

echo "<b>docker openresty Test.</b>" >> /share/Container/gateway-web/www/index.html


weiyigeek.top-持久化目录文件结构图

Step 3.在NAS中创建Docker-Compose资源清单文件,用于部署Openresty容器应用。

代码语言:javascript
复制
# 建议创建一个 bridge 网络,避免容器间相互影响,后续需要OpenResty代理的,都安装部署的应用都加入到该网络中。
docker network create --driver bridge --subnet 172.25.0.0/24 --gateway 172.25.0.1 appnet

7be4b7f26e819c17eb8ba8c19aeb3423d741d5003697f322907530cf898c7f82

资源清单文件,根据实际物理目录修改映射目录哟!

tee /share/Container/gateway-web/docker-compose.yaml <<'EOF'
version: '3.9'
services:
gateway-web:
container_name: openresty
image: registry.cn-hangzhou.aliyuncs.com/weiyigeek/openresty:1.25.3.1-4-alpine-apk
ports:
- 80:80
- 443:443
environment:
- TZ=Asia/Shanghai
volumes:
- /share/Container/gateway-web/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf
- /share/Container/gateway-web/conf.d:/etc/nginx/conf.d
- /share/Container/gateway-web/cert:/etc/nginx/cert
- /share/Container/gateway-web/www:/usr/local/openresty/nginx/html
networks:
- appnet

networks:
appnet:
external: true
EOF


weiyigeek.top-使用QNAP中Container Station创建容器图

Step 4.部署成功后将看到创建的 Openresty 容器应用,如下图所示:


weiyigeek.top-在NAS中查看部署的 Openresty 容器图

Step 5.浏览器访问 NAS 地址 IP:80,可查看到网页中显示docker openresty Test.文字,则表示部署成功,由于此处我们还没有配置证书所以监听端口暂时只有80端口,如下图所示:


weiyigeek.top-查看Openresty容器提供的服务是否正常工作图

Step 6.下面我们继续来为 Openresty 容器配置 SSL 证书,首先你需要有一个域名,然后通过阿里云、腾讯云或者Let's Encrypt等域名服务商购生成免费的证书,这里我使用的是 letsencrypt 免费证书,配置如下图所示:

若没有域名,可以参考作者此篇《资源分享|免费注册申请永久的eu.org顶级域名创建属于自己的域名,再也不用给博客域名续费了!》文章申请免费域名,或者在腾讯、阿里进行购买,连接直达https://help.aliyun.com/zh/dws/?source=5176.11533457&userCode=uelj47qf

代码语言:javascript
复制
# 使用 ssh 或者 QNAP QTS 系统平台,上传证书到NAS中容器证书配置映射目录
cp -a weiyigeek.top.* /share/Container/gateway-web/cert/

增加 SSL 配置,

tee /share/Container/gateway-web/default.conf <<'EOF'
server {
listen 80;
listen 443 ssl;
http2 on;
server_name nas.weiyigeek.top;

charset utf-8;

SSL

ssl_certificate /etc/nginx/cert/weiyigeek.top.cer;
ssl_certificate_key /etc/nginx/cert/weiyigeek.top.key;
ssl_session_cache shared:MozSSL:10m;
ssl_session_timeout 1d;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE:ECDH:AES:HIGH:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:!NULL:!aNULL:!eNULL:!EXPORT:!PSK:!ADH:!DH:!DES:!MD5:!RC4;
ssl_prefer_server_ciphers on;

HSTS ( http 转 https )

add_header Strict-Transport-Security "max-age=15768000;includeSubDomains;preload" always;

CORS

add_header Access-Control-Allow-Origin 'https://blog.weiyigeek.top';
add_header Access-Control-Allow-Methods 'GET,POST,OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

XXS-Protection

add_header X-XSS-Protection "1; mode=block";

#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/local/openresty/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/openresty/nginx/html;
}
}
EOF


weiyigeek.top-Openresty容器SSL配置图

Step 7.修改完毕后在 QNAP QTS 平台下,重启 Openresty 容器应用,如下图所示:

代码语言:javascript
复制
/ # nginx -s reload
2024/06/26 01:31:39 [notice] 56#56: signal process started


weiyigeek.top-热重载Openresty服务图

Step 8.配置Windows本地DNS硬解析 C:\Windows\System32\drivers\etc\hosts ,末尾追加10.10.107.250 nas.weiyigeek.top保存退出,然后在浏览器中输入 nas.weiyigeek.top 访问,如下图所示则配置成功:


weiyigeek.top-验证Openresty容器SSL证书配置图

至此在QNAP中部署OpenResty容器,并配置SSL证书完成,实践完成,后续作者将发布更多 OpenResty 实用技巧,一定要关注作者哟!

温馨提示:作者最近10年的工作学习笔记(涉及网络、安全、运维、开发),需要学习实践笔记的看友,可添加作者账号[WeiyiGeeker],当前价格¥199,除了获得从业笔记的同时还可进行问题答疑以及每月远程技术支持,希望大家多多支持,收获定大于付出!