海运的博客

openresty/nginx lua动态更新stream upstream/tcp udp端口转发服务器

发布时间:February 7, 2022 // 分类: // No Comments

有一应用需动态更新目标的ip和端口,使用nginx/openresty tcp/udp端口转发配合lua扩展很方便实现。

stream {
    lua_shared_dict ups_dict 1m;
    lua_shared_dict ups_list 1m;
    lua_add_variable $ups_name;
    #当nginx启动或reload时读取配置文件内upstream列表到lua_shared_dict,更新后端的时候判断是否有效
    init_by_lua_block {
       ngx.shared.ups_list:flush_all()
       local file = "/etc/nginx/stream.conf"
       local f = io.open(file, "r")
       local content = f:read("*a")
       f:close()
       for substr in string.gmatch(content, "upstream%s+([%w-_]+)%s+%{") do
           ngx.log(ngx.WARN, substr)
           ngx.shared.ups_list:set(substr, 1)
       end
    }
  
    log_format main '$remote_addr [$time_local] '
                    '$protocol $status $bytes_sent $bytes_received '
                    '$session_time "$upstream_addr" '
                    '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
    access_log /run/log/nginx/dns_access.log main;
    error_log  /run/log/nginx/dns_error.log error;
    #log level: debug, info, notice, warn, error (default), crit, alert, and emerg.

    upstream default_tcp {
        server 127.0.0.1:53;
        server 127.0.0.1:55;
    }
    upstream default_udp {
        server 10.0.1.1:53;
        server 10.0.2.1:53;
    }
    upstream default_udp2 {
        server 10.0.3.1:53;
        server 10.0.3.2:53;
    }
    upstream test1_tcp {
        server 127.0.0.1:53;
    }
    upstream test1_udp {
        server 10.0.1.1:53;
    }
    upstream test1_udp2 {
        server 10.0.3.2:53;
    }
    upstream test2_tcp {
        server 127.0.0.1:55;
    }
    upstream test2_udp {
        server 10.0.2.1:53;
    }
    upstream test2_udp2 {
        server 10.0.3.1:53;
    }

    server {
        listen     53000 udp;
        preread_by_lua_block {
            assert(not ngx.var.ups_name)
            local ups = ngx.shared.ups_dict:get("ups_name")
            if ups ~= nil then
                ngx.log(ngx.WARN, "udp 53000 use " .. ups .. " upstream")
                ngx.var.ups_name = ups .. "_udp"
            else
                ngx.log(ngx.WARN, "udp 53000 use default upstream")
                ngx.var.ups_name = "default_udp"
            end
        }
        proxy_pass $ups_name;
        proxy_responses 1; #当返回一个udp数据包时就关闭连接,或proxy_timeout时间内无数据关闭连接
        proxy_connect_timeout 1s;
        proxy_timeout 5s;
    }
    server {
        listen     53000;
        preread_by_lua_block {
            assert(not ngx.var.ups_name)
            local ups = ngx.shared.ups_dict:get("ups_name")
            if ups ~= nil then
                ngx.log(ngx.WARN, "tcp 53000 use " .. ups .. " upstream")
                ngx.var.ups_name = ups .. "_tcp"
            else
                ngx.log(ngx.WARN, "tcp 53000 use default upstream")
                ngx.var.ups_name = "default_tcp"
            end
        }
        proxy_pass $ups_name;
        #proxy_responses 1; #当返回一个udp数据包时就关闭连接,或proxy_timeout时间内无数据关闭连接
        proxy_connect_timeout 1s;
        proxy_timeout 5s;
    }
    server {
        listen     53001 udp;
        preread_by_lua_block {
            assert(not ngx.var.ups_name)
            local ups = ngx.shared.ups_dict:get("ups_name")
            if ups ~= nil then
                ngx.log(ngx.WARN, "udp 53001 use " .. ups .. " upstream")
                ngx.var.ups_name = ups .. "_udp2"
            else
                ngx.log(ngx.WARN, "udp 53001 use default upstream")
                ngx.var.ups_name = "default_udp2"
            end
        }
        proxy_pass $ups_name;
        proxy_responses 1; #当返回一个udp数据包时就关闭连接,或proxy_timeout时间内无数据关闭连接
        proxy_connect_timeout 1s;
        proxy_timeout 5s;
    }


    server {
        listen 53001;

        content_by_lua_block {
            local sock = assert(ngx.req.socket(true))
            local data = sock:receive()
            local args, err = ngx.decode_args(data, 0)
            if err == nil then
                for k,v in pairs(args) do
                    --ngx.say(v)
                    ip = v:match("(%d+%.%d+%.%d+%.%d+%:%d+)")
                    if ip ~= nil then
                        local sus, err = ngx.shared.ups_dict:set(k, ip)
                        if sus then
                            ngx.say("set upstream sus: " .. k .. "=" .. ip)
                        else
                            ngx.say(err)
                        end
                    end
                end
            end
        }
        access_log off;
    }
    server {
        listen 53002;

        content_by_lua_block {
            local sock = assert(ngx.req.socket(true))
            local data = sock:receive()
            if data then
                local args, err = ngx.decode_args(data, 0)
                if err == nil then
                    for k,v in pairs(args) do
                        --ngx.say(v)
                        --if k == "name" and type(v) == "string" and v:find("dns") then
                        if k == "name" and type(v) == "string" and ngx.shared.ups_list:get(v .. "_udp")  then
                            local sus, err = ngx.shared.ups_dict:set("ups_name", v)
                            if sus then
                                ngx.say("set upstream sus: " .. k .. "=" .. v)
                                ngx.log(ngx.WARN, "set upstream sus: " .. k .. "=" .. v)
                            else
                                ngx.say(err)
                            end
                        end
                    end
                end
            end
        }
        access_log off;
    }
}

使用nc测试设置nginx转发使用的后端upstream名称:

nc 127.0.0.1 53002
name=test1
set upstream sus: name=test1

也可通过53001端口设置目标ip:port,然后proxy_pass即可。
参考:
https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md
https://xiangxianzui.github.io/2017/11/nginx-lua%E5%8A%A8%E6%80%81%E6%94%B9%E5%8F%98upstream/

nginx配置webdav及使用curl测试

发布时间:February 2, 2021 // 分类:Nginx // No Comments

需安装http-dav-ext扩展,有时使用非标准webdav客户端删除目录时最后不带/,nginx删除目录失败返回409,alias不支持rewrite使用root。

  location /webdav/ {
    satisfy any;
    allow 127.0.0.1;
    deny all;
    #root /;
    #if (-d $request_filename) { rewrite ^(.*[^/])$ $1/ break; }
    alias /webdav/;
    dav_methods PUT DELETE MKCOL COPY MOVE;
    dav_ext_methods PROPFIND OPTIONS;
    dav_access user:rw group:r all:r;
    create_full_put_path  on;
    port_in_redirect off;
    autoindex on;
    autoindex_localtime on;
    charset utf-8;
    auth_basic "Login";
    auth_basic_user_file htpasswd;
  }

配置nginx webdav不同用户使用不同的家目录:

map $remote_user $home {
  default      $remote_user;
  ''           guest;
}
server {
  listen 80 default_server;
  listen [::]:80 default_server;
  server_name _;

  root /var/www/html;
  index index.html index.htm index.nginx-debian.html;

  try_files $uri /;

  location / {
    #if (-d $request_filename) { rewrite ^(.*[^/])$ $1/ break; }
    alias /data/webdav/$home/;
    #dav_methods PUT DELETE MKCOL COPY MOVE;
    dav_ext_methods PROPFIND OPTIONS;
    dav_access user:r group:r all:r;
    create_full_put_path on;
    port_in_redirect off;
    autoindex on;
    autoindex_localtime on;
    charset utf-8;
    auth_basic "Login";
    auth_basic_user_file htpasswd;
  }

  #access_log off;
  access_log /var/log/nginx/webdav.log;
  error_log  /var/log/nginx/webdav_error.log;
}

使用curl测试webdav:
新建目录,注意最后一定要带/,不然返回409,MKCOL can create a collection only

curl -X MKCOL https://www.haiyun.me/webdav/test/

上传文件:

curl -T filename https://www.haiyun.me/webdav/

重命名文件:

curl -X MOVE --header 'Destination:https://www.haiyun.me/webdav/newname' https://www.haiyun.me/webdav/filename

删除文件:

curl -X DELETE https://www.haiyun.me/webdav/filename

typecho配置nginx使用fastcgi cache缓存加速

发布时间:December 16, 2020 // 分类:Nginx // No Comments

安装nginx依赖扩展,当typecho更新时调用http-cache-purge删除缓存,当命中缓存时调用lua清除set-cookie head,防止缓存的设置cookie header发送给所有人。

apt install libnginx-mod-http-cache-purge libnginx-mod-http-lua

http内添加:

    fastcgi_cache_path /dev/shm/fastcgi_cache_dir levels=1:2 keys_zone=phpcache:100m inactive=30d max_size=200M;
    fastcgi_temp_path /dev/shm/fastcgi_cache_dir/temp;
    fastcgi_cache_use_stale error timeout invalid_header http_500;
    fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

修改server段:

  set $skip_cache 0;
  #跳过缓存,post请求
  if ($request_method = POST) {
    set $skip_cache 1;
  }
  #url包含参数
  if ($query_string != "") {
    set $skip_cache 1;
  }
  #指定url
  if ($request_uri ~* ^(/admin/|/action/|/search/|/feed/)) {
    set $skip_cache 1;
  }
  #登录用户
  if ($http_cookie ~* "typecho_authCode") {
    set $skip_cache 1;
  }
  #$uri经过重写后会改变,通过lua提前复制到$permalink
  set_by_lua_block $permalink {
    return ngx.var.uri
  }
  location ~ .*\.php$
  {
    try_files $uri =404;
    astcgi_pass  127.0.0.1:9000;
    fastcgi_index index.php;
    include fastcgi.conf;

    fastcgi_cache_key $scheme$request_method$host$permalink;
    add_header Cache-State $upstream_cache_status;
    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache $skip_cache;
    fastcgi_cache phpcache;
    fastcgi_cache_valid 200 301 302 30d;

    log_by_lua_file "/etc/nginx/ngx_lua_reqstatus/hook.lua";
    header_filter_by_lua_block {
      --if ngx.status == ngx.HTTP_OK then
        --ngx.header['Cache-State'] = ngx.var.upstream_cache_status
      --end
      if ngx.var.upstream_cache_status == "HIT" then
        ngx.header['Set-Cookie'] = nil
      end
    }
  }

  location ~ /xxx/_clean_cache(/.*) {
      fastcgi_cache_purge phpcache "$scheme$request_method$host$1";
  }

typecho清除缓存插件:
https://github.com/typecho-fans/plugins/tree/master/Ncache
typecho默认在用户评论后会在cookie内设置用户名和邮箱信息,并在服务端读取cookie在html内写入相关信息,这样用户信息被缓存所有人都可以看到,可参考下面方法修改模板用js读取cookie内用户信息。
https://cuojue.org/read/typecho_comments_author_javascript.html

ubuntu 20.04下nginx不支持tls1.0/tls1.1解决

发布时间:December 16, 2020 // 分类:Nginx // No Comments

在ubuntu 20.04下配置nginx ssl时怎么不支持tls1.0/1.1,确认配置文件无误怀疑是openssl的问题,原来是ubuntu 20.04/openssl 1.1.1默认禁用了不安全的tls协议,可以修改openssl配置文件开启。
patch:

--- openssl.cnf 2020-12-26 10:54:59.000000000 +0800
+++ /etc/ssl/openssl.cnf        2020-12-26 11:28:20.406439168 +0800
@@ -11,6 +11,8 @@
 # defined.
 HOME                   = .
 
+openssl_conf = default_conf
+
 # Extra OBJECT IDENTIFIER info:
 #oid_file              = $ENV::HOME/.oid
 oid_section            = new_oids
@@ -348,3 +350,13 @@
                                # (optional, default: no)
 ess_cert_id_alg                = sha1  # algorithm to compute certificate
                                # identifier (optional, default: sha1)
+
+[default_conf]
+ssl_conf = ssl_sect
+
+[ssl_sect]
+system_default = system_default_sect
+
+[system_default_sect]
+MinProtocol = TLSv1
+CipherString = DEFAULT:@SECLEVEL=1

或直接修改配置文件,openssl.cnf首部添加:

sed -i '1i openssl_conf = default_conf' /etc/ssl/openssl.cnf

尾部添加:

cat >> /etc/ssl/openssl.cnf << EOF
[default_conf]
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
MinProtocol = TLSv1
CipherString = DEFAULT:@SECLEVEL=1
EOF

使用openssl测试是否支持tls1.0和1.1:

openssl s_client -connect www.haiyun.me:443 -tls1_1
openssl s_client -connect www.haiyun.me:443 -tls1

参考:
https://askubuntu.com/questions/1233186/ubuntu-20-04-how-to-set-lower-ssl-security-level

使用Let's Encrypt签发的免费https证书

发布时间:February 2, 2018 // 分类: // No Comments

安装ssl证书获取工具certbot,安装前先删除request及urllib包,不然可以会出现No module named 'requests.packages.urllib3' 的错误:

pip uninstall requests -y
pip uninstall urllib3 -y
yum remove python-urllib3 -y
yum remove python-requests -y
yum install python-urllib3 -y
yum install python-requests -y
yum install certbot -y

centos8直接下载certbot,运行时会自动安装依赖:

wget https://dl.eff.org/certbot-auto

获取证书,成功后证书文件在 /etc/letsencrypt/live/haiyun.me/目录下

certbot certonly --webroot --email sss@haiyun.me --agree-tos --no-eff-email -w /var/www/www.haiyun.me -d haiyun.me -d www.haiyun.me

配置nginx:

  listen       443 default ssl ;
  server_name www.haiyun.me haiyun.me;
  index index.html index.htm index.php; 
  root  /var/www/www.haiyun.me;
  ssl_certificate /etc/letsencrypt/live/haiyun.me/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/haiyun.me/privkey.pem;
  ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers         HIGH:!aNULL:!MD5;
  ssl_prefer_server_ciphers   on;

由于Let's Encrypt的免费证书有效期为3个月,60天可以更新,使用cron定时任务自动更新证书:

00 01 * * * certbot renew --renew-hook "nginx -s reload"

吊销证书:

certbot revoke --cert-path /etc/letsencrypt/live/haiyun.me/cert.pem --key-path /etc/letsencrypt/live/haiyun.me/privkey.pem 

迁移服务器备份:

cd /etc/letsencrypt
tar zcf letsencrypt.tar.gz archive live renewal
分类
最新文章
最近回复
  • opnfense: 谢谢博主!!!解决问题了!!!我之前一直以为内置的odhcp6就是唯一管理ipv6的方式
  • liyk: 这个方法获取的IPv6大概20分钟之后就会失效,默认路由先消失,然后Global IPV6再消失
  • 海运: 不好意思,没有。
  • zongboa: 您好,請問一下有immortalwrt設定guest Wi-Fi的GUI教學嗎?感謝您。
  • 海运: 恩山有很多。
  • swsend: 大佬可以分享一下固件吗,谢谢。
  • Jimmy: 方法一 nghtp3步骤需要改成如下才能编译成功: git clone https://git...
  • 海运: 地址格式和udpxy一样,udpxy和msd_lite能用这个就能用。
  • 1: 怎么用 编译后的程序在家里路由器内任意一台设备上运行就可以吗?比如笔记本电脑 m参数是笔记本的...
  • 孤狼: ups_status_set: seems that UPS [BK650M2-CH] is ...