利用 openresty 打造 IP 地址查询接口

前言

OpenResty 是基于 Nginx 的高性能 Web 应用服务器,它集成了 Lua 编程语言,使开发人员能够快速构建灵活、可扩展的 Web 应用程序。借助 OpenResty,您可以利用 Nginx 强大的性能特点和 Lua 的编程能力来处理复杂的业务逻辑,并实现高并发和高效率的请求处理。同时,OpenResty 还提供了丰富的 Lua 库和模块,简化开发过程,如处理 HTTP 请求、操作数据库等。总之,OpenResty 是一个强大而简洁的工具,适用于构建高性能的 Web 应用程序。

环境

本文章使用的是腾讯云CVM服务器。CVM可提供多种类型的实例、操作系统和软件包。各实例中的 CPU、内存、硬盘和带宽可以灵活调整,以满足您应用程序的资源需要。同时腾讯云市场提供第三方镜像及软件供您选择。本次实验系统为Debian 12 。OpenResty版本为 1.21.4.2


安装OPENRESTY

本次是基于源码编译安装,也可以使用包管理器安装

编译环境

bash 复制代码
root@VM-0-3-debian:~# lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 12 (bookworm)
Release:        12
Codename:       bookworm

安装依赖

bash 复制代码
sudo apt update
sudo apt install -y libgeoip-dev libpcre3 libpcre3-dev  openssl libssl-dev  libmaxminddb0 libmaxminddb-dev mmdb-bin libgeoip1 libgeoip-dev geoip-bin  build-essential  gcc libtool autoconf zlib1g zlib1g-dev git

安装libmaxminddb

libmaxminddb 是一个 C 语言库,用于解析 MaxMind DB 格式的 IP 地理位置数据库。

bash 复制代码
#path ~/openresty
wget https://github.com/maxmind/libmaxminddb/releases/download/1.7.1/libmaxminddb-1.7.1.tar.gz
tar -xzvf libmaxminddb-1.7.1.tar.gz
cd libmaxminddb-1.7.1
./configure
make
make check
sudo make install
sudo sh -c "echo /usr/local/lib  >> /etc/ld.so.conf.d/local.conf"
sudo ldconfig

准备openssl、pcre和zlib

查询openssl版本

bash 复制代码
root@VM-0-3-debian:~# openssl version
OpenSSL 3.0.9 30 May 2023 (Library: OpenSSL 3.0.9 30 May 2023)

我们手动下载对应版本的openssl、pcre和zlib,注意这三个库只需要下载解压,并不需要提前进行安装。

bash 复制代码
#path ~/openresty
# 下载
wget https://www.openssl.org/source/openssl-3.0.9.tar.gz
wget http://ftp.cs.stanford.edu/pub/exim/pcre/pcre-8.45.tar.gz
wget http://www.zlib.net/zlib-1.3.tar.gz

# 解压
tar -zxvf openssl-3.0.9.tar.gz
tar -zxvf pcre-8.45.tar.gz
tar -zxvf zlib-1.3.tar.gz

下载ngx_http_geoip2_module

ngx_http_geoip2_module 是一个用于 Nginx 的第三方模块,它提供了对 MaxMind GeoIP2 数据库的支持。

bash 复制代码
#path ~/openresty
git clone https://github.com/leev/ngx_http_geoip2_module.git

创建用户&&组&&目录

bash 复制代码
groupadd nginx
useradd -g nginx -s /sbin/nologin -M nginx
mkdir -p /var/cache/nginx

下载openresty

bash 复制代码
#path ~/openresty
wget https://openresty.org/download/openresty-1.21.4.2.tar.gz
tar -zxvf openresty-1.21.4.2.tar.gz

编译安装

我们可以自定义编译安装的模块,这里可以查看openresty模块的官方说明或使用./configure --help

bash 复制代码
#配置和准备 软件包
#path ~/openresty/openresty-1.21.4.2
./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=nginx \
--group=nginx \
--with-compat \
--with-file-aio \
--with-threads \
--with-http_addition_module \
--with-http_auth_request_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_mp4_module \
--with-http_random_index_module \
--with-http_realip_module \
--with-http_secure_link_module \
--with-http_slice_module \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_sub_module \
--with-http_v2_module \
--with-mail \
--with-mail_ssl_module \
--with-stream \
--with-stream_realip_module \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-luajit \
--with-pcre-jit \
--with-http_geoip_module \
--with-http_dav_module \
--add-module=/root/openresty/ngx_http_geoip2_module  \
--with-openssl=/root/openresty/openssl-3.0.9 \
--with-zlib=/root/openresty/zlib-1.3 \
--with-pcre=/root/openresty/pcre-8.45

运行gmake 命令来编译软件包,最后使用 gmake install 命令来安装它

bash 复制代码
gmake
gmake install

配置环境变量

~/.bashrc文件中添加环境变量,然后执行source ~/.bashrc使其生效。

bash 复制代码
#path ~/.bashrc
vim ~/.bashrc
export PATH=$PATH:/etc/nginx/bin
source ~/.bashrc

配置systemctl管理openresty

/etc/systemd/system/nginx.service目录下创建nginx.service文件。

bash 复制代码
#path /etc/systemd/system/nginx.service
cat > /etc/systemd/system/nginx.service << EOF
[Unit]
Description=Nginx(OpenResty ) - high performance web server
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/sh -c "/bin/kill -s HUP "
ExecStop=/bin/sh -c "/bin/kill -s TERM "
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
EOF

然后执行systemctl daemon-reload使其生效。 执行systemctl enable nginx使其开机自启。 执行systemctl start nginx启动openresty。

bash 复制代码
# 一些常用命令
systemctl status nginx   #查看openresty状态。
systemctl stop nginx     #停止openresty。
systemctl restart nginx  #重启openresty。

打开浏览器访问http://ip:80,如果出现下面页面则说明安装成功。

OpenResty操作命令

openresty的操作指令和nginx是完全一致的。具体如下:

bash 复制代码
root@VM-0-15-debian:~# nginx -h
nginx version: openresty/1.21.4.2
Usage: nginx [-?hvVtTq] [-s signal] [-p prefix]
             [-e filename] [-c filename] [-g directives]

Options:
  -?,-h         : this help
  -v            : show version and exit
  -V            : show version and configure options then exit
  -t            : test configuration and exit
  -T            : test configuration, dump it and exit
  -q            : suppress non-error messages during configuration testing
  -s signal     : send signal to a master process: stop, quit, reopen, reload
  -p prefix     : set prefix path (default: /etc/nginx/nginx/)
  -e filename   : set error log file (default: /var/log/nginx/error.log)
  -c filename   : set configuration file (default: /etc/nginx/nginx.conf)
  -g directives : set global directives out of configuration file

配置openresty

IP数据库GeoLite2-City,下载后放在/etc/nginx/goeip2/目录下。
配置文件路径/etc/nginx/nginx.conf,下面是我配置的文件,可以根据自己的需求进行修改。

conf 复制代码
#path /etc/nginx/nginx.conf
# 指定启动nginx使用的用户(不指定为nobody)
user  nginx;

# 定义作为web服务器/反向代理服务器时的 worder process 进程数
worker_processes    auto;
# 开启多核支持,且自动根据CPU个数均匀分配 worder process 进程数
worker_cpu_affinity auto;
# 指定一个nginx进程可以打开的最多文件描述符数目
worker_rlimit_nofile    65535;
# error_log配置,等级类型:[ debug | info | notice | warn | error | crit ]
error_log  /var/log/nginx/error.log  notice;
# nginx的进程pid位置;
pid        /var/run/nginx.pid;




# 连接处理相关设置
events {
    # 使用epoll的 I/O 模型,必开项,极其有利于性能
    use            epoll;
    # 设置是否允许一个worker可以接受多个请求,默认是off;
    # 值为OFF时,一个worker process进程一次只接收一个请求,由master进程自动分配worker(nginx精于此道,故建议设置为off);
    # 值为ON则一次可接收所有请求,可避免master进程额外调度,但是在高瞬时值的情况下可能导致tcp flood;
    multi_accept off;
    # 每个工作进程的并发连接数(默认为1024)
    # 理论上nginx最大连接数 = worker_processes * worker_connections
    worker_connections 65535;


}

http {
    ################################ngx_lua_waf web应用防火墙################################

    # ##WAF 配置资源引用开始
    # lua_package_path "/etc/nginx/site/lualib/?.lua;;";
    # lua_shared_dict limit 20m;
    # # init_by_lua_file  /etc/nginx/luaconf/init.lua; 
    # # access_by_lua_file /etc/nginx/luaconf/waf.lua;
    # lua_code_cache on;

    # # Set Prometheus global dict
    # lua_shared_dict prometheus_metrics 10M; #init 10M memory
    # lua_shared_dict uri_by_host 10M;
    # lua_shared_dict global_set 1M;


    ################################ngx_lua_waf web应用防火墙################################
    
    charset utf-8;


    # mime.types 指定了nginx可以接受的 Content-Type,该文件默认位于nginx.conf的同级目录
    include       /etc/nginx/mime.types;
    # 设置默认文件类型,application/octet-stream 表示未知的应用程序文件,浏览器一般不会自动执行或询问执行
    default_type  application/octet-stream;


################################获取访问用户真实IP(而不是CDN节点IP)################################
    set_real_ip_from 0.0.0.0/0;
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;




################################IP数据库################################

    geoip2 /etc/nginx/goeip2/GeoLite2-City.mmdb {
        auto_reload 5m;
        $geoip2_data_country_code country iso_code;
        $geoip2_data_country_name country names zh-CN;
        $geoip2_data_province_name subdivisions 0 names zh-CN;
        $geoip2_data_city_name city names zh-CN;
        $geoip2_data_location_latitude location latitude;
        $geoip2_data_location_longitude location longitude;
    }

################################设置日志的记录格式 ################################
    log_format main  escape=none '$geoip2_data_country_name - $geoip2_data_city_name - '
                      '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';



    # 不记录404错误的日志
    log_not_found   off;
    # 隐藏nginx版本号
    server_tokens   off;
    # 开启0拷贝,提高文件传输效率
    sendfile    on;
    # 配合 sendfile 使用,启用后数据包会累计到一定大小之后才会发送,减小额外开销,提高网络效率;
    tcp_nopush  on;
    # 启用后表示禁用 Nagle 算法,尽快发送数据
    # 与 tcp_nopush 结合使用的效果是:先填满包,再尽快发送
    # Nginx 只会针对处于 keep-alive 状态的 TCP 连接才会启用 tcp_nodelay
    tcp_nodelay on;
    # 指定客户端与服务端建立连接后发送 request body 的超时时间,超时Nginx将返回http 408
    client_body_timeout 10;
    # 开启从client到nginx的连接长连接支持,指定每个 TCP 连接最多可以保持多长时间
    # keepalive_timeout的值应该比 client_body_timeout 大
    keepalive_timeout   65;
    # keepalive_requests指令用于设置一个keep-alive连接上可以服务的请求的最大数量,当最大请求数量达到时,连接将被关闭
    keepalive_requests  1000;


################################客户端请求头部的缓冲区大小,设置等于系统分页大小即可,如果header过大可根据实际情况调整;################################
    # 查看系统分页:getconf PAGESIZE
    client_header_buffer_size       32k;
    # 设置客户端请求的Header头缓冲区大小,如果客户端的Cookie信息较大,按需增加
    large_client_header_buffers     4 64k;
    # 优化读取\$request_body变量时的I/O性能
    client_body_in_single_buffer    on;
    # 设定request body的缓冲大小,仅在 Nginx被设置成使用内存缓冲时有效(使用文件缓冲时该参数无效)
    client_body_buffer_size     128k;
    # 开启proxy忽略客户端中断,避免499错误
    proxy_ignore_client_abort       on;
    # 默认的情况下nginx引用header变量时不能使用带下划线的变量,设置underscores_in_headers为 on取消该限制
    underscores_in_headers      on;
    # 默认的情况下nginx会忽略带下划线的变量,设置ignore_invalid_headers为off取消该限制
    ignore_invalid_headers      off;
    # 设置客户端向服务端发送一个完整的 request header 的超时时间,优化弱网场景下nginx的性能
    client_header_timeout   10;
    # 设置向客户端传输数据的超时时间
    send_timeout        60;
    # 用于启用文件功能时用限制文件大小;
    client_max_body_size    50m;



################################ 文件压缩配置,对文本文件效果较好,对图像类应用效果一般反而徒增服务器资源消耗################################
    gzip        on;
    # 兼容http 1.0
    gzip_http_version   1.0;
    # 压缩比,数值越大:压缩的程度越高、空间占用越低、压缩效率越低、资源消耗越大
    gzip_comp_level 6;
    # 设置压缩门限,小于该长度将不会进行压缩动作(数据过小的情况下,压缩效果不明显)
    gzip_min_length 1k;
    # 用于在nginx作为反向代理时,根据请求头中的"Via"字段决定是否启用压缩功能,默认值为off,any表示对所有请求启动压缩;
    gzip_proxied    any;
    # 用于在启动gzip压缩功能时,在http响应中添加Vary: Accept-Encoding头字段告知接收方使用了gzip压缩;
    gzip_vary       on;
    # 当Agent为IE6时禁用压缩:IE6对Gzip不友好,所以不压缩
    gzip_disable    msie6;
    # 设置系统用于存储gzip的压缩结果数据流的缓存大小(4 4k 代表以4k为单位,按照原始数据大小以4k为单位的4倍申请内存)
    gzip_buffers    4 64k;
    # 指定需要压缩的文件mime类型
    gzip_types      text/xml text/plain text/css application/javascript application/x-javascript application/xml application/json application/rss+xml;
    
    
################################ 作为反向代理服务器配置 ################################

    # 当请求未携带"Host"请求头时将Host设置为虚拟主机的主域名
    # proxy_set_header        Host \$host;
    # 设置真实客户端IP
    # proxy_set_header        X-Real-IP \$remote_addr;
    # 简称XFF头,即HTTP的请求端真实的IP,在有前置cdn或者负载均衡可能会被修改;如果要提取客户端真实IP,需要根据实际情况调整,如若后端程序获得对X-Forwarded-For兼容性不好的话(没有考虑到X-Forwarded-For含有多个IP的情况),建议设置为:\$http_x_forwarded_for
    # proxy_set_header        X-Forwarded-For \$proxy_add_x_forwarded_for;
    
    # 启用nginx和后端server(upstream)之间长连接支持(必设项,否则很影响nginx性能),HTTP协议中从1.1版本才支持长连接;启用时需要评估upstream的keepalive参数(默认是关闭的,比较懒的同学可以设置为500)
    proxy_http_version 1.1;
    # 为了兼容老的协议以及防止http头中有Connection close导致的keepalive失效,需要及时清掉HTTP头部的Connection;
    # 该参数决定了访问完成后,后端server后如何处理本次连接,默认配置是主动close(会给后端server带来大量的TIME_WAIT连接,降低后端server性能),设置为""结合proxy_http_version设置连接保持(长连接);
    proxy_set_header Connection "";
    # 用于对发送给客户端的URL进行修改,使用不到的话可以关闭
    proxy_redirect          off;
    # 设置缓冲区的大小和数量,用于放置被代理的后端服务器取得的响应内容
    proxy_buffers           64 8k;
    # 设置和后端建立连接的超时时间,单位秒
    proxy_connect_timeout   60;
    # 设置Nginx向后端被代理服务器发送read请求后,等待响应的超时时间,默认60秒
    proxy_read_timeout 60;
    # 设置Nginx向后端被代理服务器发送write请求后,等待响应的超时时间,默认60秒
    proxy_send_timeout 60;
    # 用于配置存放HTTP报文头的哈希表容量,默认为512个字符。一般都设置为1024,这个大小是哈希表的总大小,
    #设定了这个参数Nginx不是一次全部申请出来,需要用的时候才会申请;
    #但是当真正需要使用的时候也不是一次全部申请,而是会设置一个单次申请最大值(proxy_headers_hash_bucket_size)
    proxy_headers_hash_max_size 1024;
    # 用于设置Nginx服务器申请存放HTTP报文头的哈希表容量的单位大小,默认为64个字符。一般配置为128。
    #这个大小是单次申请最多申请多大,也就是每次用需要申请,但是每次申请最大申请多少,整个哈希表大小不可超过上面设置的值。
    proxy_headers_hash_bucket_size 128;
    # 设置缓存临时目录
    proxy_temp_path /var/cache/nginx/proxy_temp;
    # 设置缓存目录、目录结构及缓存数据保留策略
    proxy_cache_path    /var/cache/nginx/proxy_cache levels=1:2 keys_zone=cache_one:512m inactive=1d max_size=2g;



################################ 预防 DDOS 攻击配置策略 ################################
    #limit_req_zone          \$binary_remote_addr  zone=req:20m   rate=3r/s;
    #limit_req               zone=req  burst=60;
    #limit_zone              conn \$binary_remote_addr  20m;
    #limit_conn              conn 5;
    #limit_rate              50k;



################################设置nginx可以捕获的服务器名字(server_name)的最大数量################################
    server_names_hash_max_size    1024;


################################设置nginx中server_name支持的最大长度################################
    server_names_hash_bucket_size 128;
    include /etc/nginx/conf.d/*.conf;
}

配置ip查询接口

/etc/nginx/conf.d/目录下创建ip.conf文件并修改为下面配置内容。

conf 复制代码
#path /etc/nginx/conf.d/ip.conf

server {

    listen       80;
    server_name  localhost;

    #listen 443 ssl http2;
    #listen [::]:443 ssl http2;
    #ssl_certificate /etc/nginx/conf.d/ssl/cert.pem;
    #ssl_certificate_key /etc/nginx/conf.d/ssl/key.pem;
    # server_name xxx.xxx.xxx;


    access_log /var/log/nginx/ip.log main;


    default_type text/plain;

    location / {
        if ($http_user_agent ~* "curl|wget") {
            rewrite / /ip last;
        }
        rewrite / /info last;
    }

    location /ip {
        echo $remote_addr;
    }
    location /country_code {
        echo $geoip2_data_country_code;
    }
    location /country {
        echo $geoip2_data_country_name;
    }
    location /province {
        echo $geoip2_data_province_name;
    }
    location /city {
        echo $geoip2_data_city_name;
    }
    location /latitude {
        echo $geoip2_data_location_latitude;
    }
    location /longitude {
        echo $geoip2_data_location_longitude;
    }
    location /ua {
        echo $http_user_agent;
    }

    location /info {
        echo "IP ADDRESS   : $remote_addr";
        echo " ";
        echo "COUNTRY CODE : $geoip2_data_country_code";
        echo "COUNTRY      : $geoip2_data_country_name";
        echo "PROVINCE     : $geoip2_data_province_name";
        echo "CITY         : $geoip2_data_city_name";
        echo " ";
        echo "LATITUDE     : $geoip2_data_location_latitude";
        echo "LONGITUDE    : $geoip2_data_location_longitude";
        echo " ";
        echo "USER AGENT   : $http_user_agent";
        echo "";
        echo "Use /help for more information";
    }

location /help {

    echo "/                    IP INFO (browser) | IP ADDRESS (wget/curl)";
    echo " ";
    echo "/ip                  IP ADDRESS";
    echo " ";
    echo "/info                IP INFO";
    echo "/json                IP INFO (JSON)";
    echo " ";
    echo "/country_code        COUNTRY CODE";
    echo "/country             COUNTRY NAME";
    echo "/province            PROVINCE NAME";
    echo "/city                CITY NAME";
    echo " ";
    echo "/longitude           LONGITUDE";
    echo "/latitude            LATITUDE";
    echo " ";
    echo "/ua                  USER AGENT";
    echo " ";
    echo "Advanced:";
    echo "/{cmd}/{ip}          FIND IP INFO, eg: /info/1.1.1.1";
}

    location /json {
        default_type application/json;
        return 200 '{
            "ip": "$remote_addr",
            "country_code": "$geoip2_data_country_code",
            "country": "$geoip2_data_country_name",
            "province": "$geoip2_data_province_name",
            "city": "$geoip2_data_city_name",
            "latitude": "$geoip2_data_location_latitude",
            "longitude": "$geoip2_data_location_longitude",
            "ua": "$http_user_agent",
            "forwarded": "$http_x_forwarded_for"
        }';
    }


    location ~ ^/(\w+/)?(\d+\..+|\w*:.+)$ {
        proxy_pass http://127.0.0.1/$1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $2;
    }


}

执行nginx -s reload,访问http://ip:80,如果出现下面页面则说明配置成功。

配置logrotate自动分割压缩日志

创建/etc/logrotate.d/nginx文件并修改为下面配置内容。

conf 复制代码
#path /etc/logrotate.d/nginx
/var/log/nginx/*.log {
        daily
        missingok
        rotate 52
        compress
        delaycompress
        notifempty
        create 640 nginx adm
        sharedscripts
        postrotate
                if [ -f /var/run/nginx.pid ]; then
                        kill -USR1 `cat /var/run/nginx.pid`
                fi
        endscript
}

手动运行logrotate命令来测试配置是否正确:

bash 复制代码
logrotate -f /etc/logrotate.d/nginx

确认一切正常后,您可以通过以下命令来实际执行logrotate并轮转日志文件

bash 复制代码
logrotate /etc/logrotate.conf

参考:openresty.org

相关推荐
denglei.11 小时前
在Nginx部署Web应用,如何保障后端API的安全
nginx·安全
苹果醋314 小时前
React系列(八)——React进阶知识点拓展
运维·vue.js·spring boot·nginx·课程设计
我要出家当道士14 小时前
Nginx单向链表 ngx_list_t
数据结构·nginx·链表·c
fat house cat_16 小时前
Linux环境下使用tomcat+nginx部署若依项目
linux·nginx·tomcat
꧁༺朝花夕逝༻꧂18 小时前
nginx-代理服务
运维·服务器·nginx
Smile_Gently18 小时前
Ubuntu环境 nginx.conf详解(二)
运维·服务器·前端·nginx·ubuntu
weixin_4495687019 小时前
Nginx区分PC端和移动端访问
运维·nginx
记得开心一点嘛21 小时前
Nginx与Tomcat之间的关系
java·nginx·tomcat
ascarl201021 小时前
【Nginx系列】---Nginx配置tcp转发
运维·tcp/ip·nginx
handsomestWei1 天前
Nginx整合Lua脚本
运维·nginx·lua