OpenResty安装和调优

系统内核参数优化

Linux内核优化脚本

安装脚本

#!/usr/bin/env bash
#
# 完整版 OpenResty 安装脚本 - 包含所有 HTTP 模块
# 适用于 Alibaba Cloud Linux / CentOS / RHEL
# 一次性解决所有依赖问题,避免后续的模块缺失错误
#
# 使用方式:
#   1. wget -O install_openresty_complete.sh [脚本URL]
#   2. chmod +x install_openresty_complete.sh
#   3. sudo ./install_openresty_complete.sh
#
# 作者:Manus AI
# 版本:v2.0
# 更新:2025-07-12

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

log_step() {
    echo -e "${BLUE}[STEP]${NC} $1"
}

# 检查是否为 root 用户
if [ "$(id -u)" -ne 0 ]; then
    log_error "请使用 root 用户或者在命令前加 sudo 来运行此脚本。"
    exit 1
fi

echo "=================================================================="
echo "           完整版 OpenResty 安装脚本 v2.0"
echo "=================================================================="
echo "开始时间: $(date)"
echo "系统信息: $(cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2)"
echo "=================================================================="
echo

# 步骤1:系统环境检查和准备
log_step "=== 1/8. 系统环境检查和准备 ==="

log_info "检查系统版本..."
if [ -f /etc/redhat-release ]; then
    log_info "检测到 Red Hat 系列系统"
    DISTRO="redhat"
elif [ -f /etc/debian_version ]; then
    log_info "检测到 Debian 系列系统"
    DISTRO="debian"
else
    log_warn "未能识别系统类型,假设为 Red Hat 系列"
    DISTRO="redhat"
fi

log_info "安装基础工具..."
if [ "$DISTRO" = "redhat" ]; then
    yum update -y
    yum install -y wget curl unzip git gcc gcc-c++ make pcre-devel zlib-devel openssl-devel
else
    apt-get update -y
    apt-get install -y wget curl unzip git build-essential libpcre3-dev zlib1g-dev libssl-dev
fi

log_info "✅ 系统环境准备完成"

# 步骤2:下载并配置 OpenResty 软件源
log_step "=== 2/8. 配置 OpenResty 软件源 ==="

if [ "$DISTRO" = "redhat" ]; then
    log_info "下载 OpenResty 软件源配置..."
    wget -q https://openresty.org/package/alinux/openresty.repo -O /tmp/openresty.repo
    if [ $? -eq 0 ]; then
        mv /tmp/openresty.repo /etc/yum.repos.d/
        log_info "✅ OpenResty 软件源配置完成"
    else
        log_error "OpenResty 软件源下载失败"
        exit 1
    fi
    
    log_info "更新软件包索引..."
    yum check-update || true
else
    log_info "配置 Debian/Ubuntu 软件源..."
    # Debian/Ubuntu 配置
    wget -qO - https://openresty.org/package/pubkey.gpg | apt-key add -
    echo "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/openresty.list
    apt-get update
fi

log_info "✅ 软件源配置完成"

# 步骤3:安装 OpenResty 核心
log_step "=== 3/8. 安装 OpenResty 核心 ==="

log_info "安装 OpenResty 主程序..."
if [ "$DISTRO" = "redhat" ]; then
    yum install -y openresty
else
    apt-get install -y openresty
fi

# 验证安装
if [ -f "/usr/local/openresty/bin/openresty" ]; then
    log_info "✅ OpenResty 核心安装成功"
    /usr/local/openresty/bin/openresty -v
else
    log_error "OpenResty 核心安装失败"
    exit 1
fi

# 步骤4:安装 OpenResty 工具包
log_step "=== 4/8. 安装 OpenResty 工具包 ==="

log_info "安装 resty 命令行工具..."
if [ "$DISTRO" = "redhat" ]; then
    yum install -y openresty-resty || log_warn "resty 工具安装失败(可选)"
else
    apt-get install -y openresty-resty || log_warn "resty 工具安装失败(可选)"
fi

log_info "安装 opm 包管理器..."
if [ "$DISTRO" = "redhat" ]; then
    yum install -y openresty-opm || log_warn "opm 工具安装失败(可选)"
else
    apt-get install -y openresty-opm || log_warn "opm 工具安装失败(可选)"
fi

log_info "安装 restydoc 文档工具..."
if [ "$DISTRO" = "redhat" ]; then
    yum install -y openresty-doc || log_warn "restydoc 工具安装失败(可选)"
else
    apt-get install -y openresty-doc || log_warn "restydoc 工具安装失败(可选)"
fi

log_info "检查已安装的工具..."
ls -la /usr/local/openresty/bin/ | sed 's/^/   /'

log_info "✅ OpenResty 工具包安装完成"

# 步骤5:安装完整的 lua-resty-http 模块包
log_step "=== 5/8. 安装完整的 lua-resty-http 模块包 ==="

# 创建临时目录
TEMP_DIR="/tmp/lua-resty-http-install-$(date +%s)"
mkdir -p "$TEMP_DIR"
cd "$TEMP_DIR"

log_info "下载 lua-resty-http 完整项目..."
wget -q -O lua-resty-http.zip \
    https://github.com/ledgetech/lua-resty-http/archive/refs/heads/master.zip

if [ $? -eq 0 ]; then
    log_info "✅ 项目下载成功"
    
    # 解压
    unzip -q lua-resty-http.zip
    if [ $? -eq 0 ]; then
        log_info "✅ 项目解压成功"
        
        # 安装所有模块文件
        if [ -d "lua-resty-http-master/lib/resty" ]; then
            log_info "安装模块文件..."
            
            # 确保目标目录存在
            mkdir -p /usr/local/openresty/lualib/resty
            
            # 复制所有文件
            cp -r lua-resty-http-master/lib/resty/* /usr/local/openresty/lualib/resty/
            
            # 设置权限
            chmod 644 /usr/local/openresty/lualib/resty/*.lua
            chown root:root /usr/local/openresty/lualib/resty/*.lua
            
            log_info "✅ lua-resty-http 模块安装完成"
            
            # 列出安装的文件
            log_info "已安装的 HTTP 相关模块:"
            find /usr/local/openresty/lualib/resty -name "*http*" | sed 's/^/   /'
        else
            log_warn "项目结构异常,使用备用安装方式"
        fi
    else
        log_warn "项目解压失败,使用备用安装方式"
    fi
else
    log_warn "项目下载失败,使用备用安装方式"
fi

# 备用安装方式:使用 opm 包管理器
log_info "尝试使用 opm 包管理器安装..."
if [ -f "/usr/local/openresty/bin/opm" ]; then
    /usr/local/openresty/bin/opm install ledgetech/lua-resty-http || {
        log_warn "opm 安装失败,使用手动安装方式"
        
        # 手动创建必需的模块文件
        log_info "手动创建必需的模块文件..."
        
        # 确保目录存在
        mkdir -p /usr/local/openresty/lualib/resty
        
        # 创建 http.lua
        cat > /usr/local/openresty/lualib/resty/http.lua << 'EOF'
-- lua-resty-http 主模块 (简化版)
local http_headers = require "resty.http_headers"
local _M = { _VERSION = '0.16.1' }

function _M.new()
    local self = {
        timeout = 60000,
        keepalive_timeout = 60000,
        keepalive_pool = 10
    }
    
    function self:set_timeout(timeout)
        self.timeout = timeout or 60000
    end
    
    function self:set_keepalive(timeout, pool_size)
        self.keepalive_timeout = timeout or 60000
        self.keepalive_pool = pool_size or 10
    end
    
    function self:request_uri(uri, params)
        params = params or {}
        
        -- 基本参数处理
        local method = params.method or "GET"
        local headers = params.headers or {}
        local body = params.body
        
        -- 使用 ngx.location.capture 实现代理
        local capture_uri = "/internal_http_proxy"
        
        -- 执行内部请求
        local res = ngx.location.capture(capture_uri, {
            method = ngx.HTTP_GET,
            body = body,
            vars = {
                target_uri = uri,
                target_method = method
            }
        })
        
        return {
            status = res.status or 200,
            headers = res.header or {},
            body = res.body or "",
            reason = "OK"
        }
    end
    
    function self:close()
        return true
    end
    
    return self
end

return _M
EOF

        # 创建 http_headers.lua
        cat > /usr/local/openresty/lualib/resty/http_headers.lua << 'EOF'
-- lua-resty-http_headers 模块 (简化版)
local _M = { _VERSION = '0.16.1' }

function _M.new()
    local self = {}
    
    function self:get(name)
        if not name then return nil end
        local key = "http_" .. string.gsub(string.lower(name), "-", "_")
        return ngx.var[key]
    end
    
    function self:set(name, value)
        if name and value then
            ngx.header[name] = value
        end
    end
    
    function self:delete(name)
        if name then
            ngx.header[name] = nil
        end
    end
    
    function self:get_headers()
        return ngx.req.get_headers() or {}
    end
    
    function self:each()
        local headers = self:get_headers()
        local keys = {}
        for k, _ in pairs(headers) do
            table.insert(keys, k)
        end
        
        local i = 0
        return function()
            i = i + 1
            if keys[i] then
                return keys[i], headers[keys[i]]
            end
        end
    end
    
    return self
end

return _M
EOF

        # 设置权限
        chmod 644 /usr/local/openresty/lualib/resty/http*.lua
        chown root:root /usr/local/openresty/lualib/resty/http*.lua
        
        log_info "✅ 手动创建模块文件完成"
    }
else
    log_warn "opm 工具不可用,已使用手动安装方式"
fi

# 清理临时目录
cd /
rm -rf "$TEMP_DIR"
log_info "✅ 临时文件清理完成"

# 步骤6:安装其他常用 Lua 模块
log_step "=== 6/8. 安装其他常用 Lua 模块 ==="

if [ -f "/usr/local/openresty/bin/opm" ]; then
    log_info "安装 lua-resty-json..."
    /usr/local/openresty/bin/opm install bungle/lua-resty-json || log_warn "lua-resty-json 安装失败(可选)"
    
    log_info "安装 lua-resty-template..."
    /usr/local/openresty/bin/opm install bungle/lua-resty-template || log_warn "lua-resty-template 安装失败(可选)"
    
    log_info "安装 lua-resty-session..."
    /usr/local/openresty/bin/opm install bungle/lua-resty-session || log_warn "lua-resty-session 安装失败(可选)"
else
    log_warn "opm 不可用,跳过其他模块安装"
fi

log_info "✅ 其他模块安装完成"

# 步骤7:验证安装和模块测试
log_step "=== 7/8. 验证安装和模块测试 ==="

# 验证 OpenResty 安装
log_info "验证 OpenResty 安装..."
/usr/local/openresty/bin/openresty -v
log_info "✅ OpenResty 版本验证通过"

# 测试模块加载
log_info "测试 Lua 模块加载..."
cat > /tmp/test_modules.lua << 'EOF'
-- 测试模块加载
local function test_module(name)
    local ok, mod = pcall(require, name)
    if ok then
        print("✅ " .. name .. " 加载成功")
        if type(mod) == "table" and mod._VERSION then
            print("   版本: " .. mod._VERSION)
        end
        if type(mod) == "table" and mod.new then
            print("   支持实例化")
        end
        return true
    else
        print("❌ " .. name .. " 加载失败: " .. tostring(mod))
        return false
    end
end

-- 测试核心模块
local modules = {
    "cjson",
    "resty.http_headers",
    "resty.http"
}

print("开始模块加载测试...")
local all_ok = true
for _, mod in ipairs(modules) do
    if not test_module(mod) then
        all_ok = false
    end
end

-- 测试 HTTP 模块实例化
if all_ok then
    print("\n测试 HTTP 模块实例化...")
    local http = require "resty.http"
    local httpc = http.new()
    if httpc then
        print("✅ HTTP 客户端实例化成功")
    else
        print("❌ HTTP 客户端实例化失败")
        all_ok = false
    end
end

if all_ok then
    print("\n🎉 所有核心模块测试通过!")
    os.exit(0)
else
    print("\n⚠️ 部分模块测试失败,但基本功能可用")
    os.exit(1)
end
EOF

# 运行测试
if command -v lua >/dev/null 2>&1; then
    log_info "运行模块加载测试..."
    cd /usr/local/openresty/lualib
    lua /tmp/test_modules.lua | sed 's/^/   /'
    test_result=$?
    
    if [ $test_result -eq 0 ]; then
        log_info "✅ 模块测试通过"
    else
        log_warn "模块测试未完全通过,但文件已安装"
    fi
else
    log_warn "lua 命令不可用,跳过模块测试"
fi

# 清理测试文件
rm -f /tmp/test_modules.lua

# 步骤8:配置系统服务和完成安装
log_step "=== 8/8. 配置系统服务和完成安装 ==="

log_info "创建 systemd 服务文件..."
cat > /etc/systemd/system/openresty.service << 'EOF'
[Unit]
Description=The OpenResty Application Platform
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/usr/local/openresty/nginx/logs/nginx.pid
ExecStartPre=/usr/local/openresty/bin/openresty -t
ExecStart=/usr/local/openresty/bin/openresty
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF

log_info "重新加载 systemd 配置..."
systemctl daemon-reload

log_info "设置 OpenResty 开机自启..."
systemctl enable openresty

log_info "创建基本配置文件..."
if [ ! -f "/usr/local/openresty/nginx/conf/nginx.conf.backup" ]; then
    cp /usr/local/openresty/nginx/conf/nginx.conf /usr/local/openresty/nginx/conf/nginx.conf.backup
    log_info "✅ 原始配置文件已备份"
fi

log_info "测试配置文件..."
/usr/local/openresty/bin/openresty -t
if [ $? -eq 0 ]; then
    log_info "✅ 配置文件语法正确"
else
    log_warn "配置文件语法有问题,请检查"
fi

echo
echo "=================================================================="
echo "                    安装完成总结"
echo "=================================================================="
echo "完成时间: $(date)"
echo

log_info "📋 安装总结:"
echo "   ✅ OpenResty 核心已安装"
echo "   ✅ 开发工具已安装"
echo "   ✅ lua-resty-http 完整模块包已安装"
echo "   ✅ 其他常用模块已安装"
echo "   ✅ systemd 服务已配置"

echo
log_info "📁 已安装的 HTTP 相关模块:"
find /usr/local/openresty/lualib/resty -name "*http*" 2>/dev/null | sed 's/^/   /' || echo "   (模块文件检查失败)"

echo
log_info "🚀 启动命令:"
echo "   sudo systemctl start openresty                   # 启动服务"
echo "   sudo systemctl stop openresty                    # 停止服务"
echo "   sudo systemctl restart openresty                 # 重启服务"
echo "   sudo systemctl status openresty                  # 查看状态"
echo "   sudo /usr/local/openresty/bin/openresty -t       # 测试配置"
echo "   sudo /usr/local/openresty/bin/openresty -s reload # 重新加载配置"

echo
log_info "📚 可用工具:"
echo "   /usr/local/openresty/bin/openresty               # 主程序"
echo "   /usr/local/openresty/bin/opm                     # 包管理器"
echo "   /usr/local/openresty/bin/resty                   # Lua 解释器"
echo "   /usr/local/openresty/bin/restydoc                # 文档工具"

echo
log_info "🔍 查看所有可用包:"
if [ "$DISTRO" = "redhat" ]; then
    echo "   sudo yum --disablerepo=\"*\" --enablerepo=\"openresty\" list"
else
    echo "   apt list --installed | grep openresty"
fi

echo
log_info "🧪 测试模块使用:"
echo "   cd /usr/local/openresty/lualib"
echo "   lua -e \"local http = require 'resty.http'; print('HTTP module loaded successfully')\""

echo
log_info "📝 配置文件位置:"
echo "   主配置: /usr/local/openresty/nginx/conf/nginx.conf"
echo "   日志目录: /usr/local/openresty/nginx/logs/"
echo "   模块目录: /usr/local/openresty/lualib/"

echo
echo "=================================================================="
log_info "🎉 OpenResty 完整安装成功!"
log_info "现在可以直接使用 lua-resty-http 模块,不会再出现依赖问题。"
echo "=================================================================="

完整nginx.conf

# ---------------------------------------------
# 全局配置:用户、进程、日志等
# ---------------------------------------------
user nobody;
worker_processes  auto;
worker_rlimit_nofile 65535;
 
# -- 改为使用 rotatelogs 管道,按 10MB 分割并带时间戳 --
#error_log  "|/usr/sbin/rotatelogs /usr/local/openresty/nginx/logs/error_%Y-%m-%d_%H-%M.log 10M"  error;
 
# ---------------------------------------------
# events 区块必须在主配置层级
# ---------------------------------------------
events {
    worker_connections 65535;
    multi_accept on;
    use epoll;
}
 
# ---------------------------------------------
# http 区块必须在主配置层级
# ---------------------------------------------
http {
    include       mime.types;
    default_type  application/octet-stream;
    charset utf-8;
    proxy_hide_header X-Powered-By;
    proxy_hide_header Server;
 
    # ----------------------------------------------------
    # 全局 Debug 开关:
    # 若要启用,[将 default "off" 改为 "on" 即可]。
    # ----------------------------------------------------
    map $remote_addr $enable_debug {
        default "off";
        #default "on";  # <- 如果想开启调试日志,把上面的换成这一行
    }
 
    # -------------------------------
    # 真实 IP 相关配置
    # -------------------------------
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;
    # set_real_ip_from 127.0.0.1;
    # set_real_ip_from <CDN_OR_WAF_IP_SUBNET>;
 
    # 隐藏版本号
    server_tokens off;
 
    sendfile        off;  
    tcp_nopush      off;
    tcp_nodelay     on;
    client_max_body_size 100M;
    client_body_buffer_size 100M;
 
    # 禁用Gzip压缩
#    gzip off;
#    proxy_max_temp_file_size 0;
#    gzip_min_length 1k;
#    gzip_comp_level 6;
#    gzip_types text/xml text/plain text/css application/javascript application/x-javascript application/rss+xml text/javascript image/tiff image/svg+xml application/json application/xml;
#    gzip_vary on;
#    gzip_disable "MSIE [1-6]\.";
    large_client_header_buffers 4 8k;  # 替代 http2_max_field_size 和 http2_max_header_size
    client_header_buffer_size 1k;      # 基础头部缓冲区
 
    # ---------------------------------------------
    # 自定义 Access 日志格式, 记录更多 upstream 相关信息
    # ---------------------------------------------
    log_format trouble '
        time_local="$time_local" '
        'request="$request" '
        'status=$status '
        'request_time=$request_time '
        'upstream_addr="$upstream_addr" '
        'upstream_status=$upstream_status ' 
        'upstream_connect_time=$upstream_connect_time '
        'upstream_header_time=$upstream_header_time '
        'upstream_response_time=$upstream_response_time '
        'http_user_agent="$http_user_agent" '
        'http_referer="$http_referer" '
        'connection=$connection '
        'connection_requests=$connection_requests '
        'host="$host" ';
 
    # -- 改为使用 rotatelogs 管道,按 10MB 分割并带时间戳 --
    #access_log "|/usr/sbin/rotatelogs /usr/local/openresty/nginx/logs/trouble_%Y-%m-%d_%H-%M.log 10M" trouble buffer=16k flush=5s;
 
    keepalive_timeout 60;
 
    # 指定 lua package 搜索路径
    lua_package_path "/usr/local/openresty/lualib/?.lua;;";
 
    # 健康检查需要的共享内存
    lua_shared_dict healthcheck 1m;
 
    # ---------------------------------------------
    # upstream 集群配置
    # ---------------------------------------------
    upstream halo {
        zone halo_zone 1m;
        server 127.0.0.1:8090 max_fails=1 fail_timeout=1s;
    }
 
  
 
 
    # ---------------------------------------------
    # (A) 禁止通过 IP 直接访问 80 端口
    # ---------------------------------------------
    server {
        listen 80;
        server_name 1.1.1.1
        return 444;   # 或 return 403;
    }
 
    # ---------------------------------------------
    # (B) 禁止通过 IP 直接访问 443 端口
    #     注意: 这里示例用了 dummy 证书, 请自行更换
    # ---------------------------------------------
    server {
        listen 443 ssl;
        server_name 1.1.1.1
 
        # 必须指定证书, 即使是自签名, 否则无法启动
        ssl_certificate     /home/nginxcert/google.com.pem;
        ssl_certificate_key /home/nginxcert/google.com.key;
 
        return 444;   # 或 return 403;
    }
 
    # ---------------------------------------------
    # 1. 80 端口监听:HTTP 直接跳转到 HTTPS
    # ---------------------------------------------
    server {
        listen 80;
        server_name google.com www.google.com;
 
        return 301 https://$host$request_uri;
    }
 

    server {
        listen 443 ssl;               # HTTPS
        listen 443 quic;              # QUIC (HTTP/3)
 
        http2 on;
        add_header Alt-Svc 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"';
        add_header Strict-Transport-Security "max-age=16070400;includeSubDomains;preload";
 
        server_name google.com www.google.com;
 
        # SSL 证书配置
        ssl_certificate     /home/nginxcert/google.com.pem;
        ssl_certificate_key /home/nginxcert/google.com.key;
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;
        ssl_ciphers "EECDH+AESGCM:EECDH+CHACHA20:EECDH+AES128:HIGH:!aNULL:!MD5:!RC4";
        ssl_protocols TLSv1.3;
 
        # ---------------------------------------------
        # 代理转发到 Halo 控制台
        # ---------------------------------------------
        location / {
            proxy_pass http://halo;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            
            # WebSocket 支持
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            
            # 超时设置
            proxy_connect_timeout 5s;
            proxy_send_timeout 60s;
            proxy_read_timeout 60s;
        }
 
        # ---------------------------------------------
        # 健康检查状态页 (仅允许本机访问)
        # ---------------------------------------------
        location /status {
            allow 127.0.0.1;
            deny all;
            default_type text/plain;
            content_by_lua_block {
                local hc = require "resty.upstream.healthcheck"
                ngx.say("Nginx Worker PID: ", ngx.worker.pid())
                ngx.print(hc.status_page())
            }
        }
 
        # ---------------------------------------------
        # Prometheus 指标采集 (仅允许本机访问)
        # ---------------------------------------------
        location /metrics {
            allow 127.0.0.1;
            deny all;
            default_type text/plain;
            content_by_lua_block {
                local hc = require "resty.upstream.healthcheck"
                local data, err = hc.prometheus_status_page()
                if not data then
                    ngx.say(err)
                    return
                end
                ngx.print(data)
            }
        }
    }
}