我如何在Nginx中使用MySQL实现动态文档根目录?

我一直在尝试找到一种方法,首先捕获环境变量HOSTNAME,然后使用MySQL查询获取并将vhosts的文档根返回给Nginx conf。我们目前在Apache中使用它们作为动态doc根,但正在迁移到Nginx。

例如nginx.conf(可能是这样的):

server {
    listen   80;
     # 获取环境变量HOSTNAME
     $hostname= ENV(HOSTNAME);
     # 执行mysql查询
    $doc_root = mysql(select docroot from table where host = '$hostname' );
     # 设置文档根
    root           /var/www/$doc_root;

..... 我正在探索使用Lua和https://github.com/openresty/lua-resty-mysql,但一直无法找出如何捕获HOSTNAME和mysql查询作为变量并将结果返回的方法。

点赞
用户312586
用户312586

首先,对于执行基本路由,使用数据库并不像是一个很好的想法 - 我建议将结果缓存在内存中,并可能定期从数据库中刷新。

其次,基本的 Nginx 配置文件只能带您走到这里 - 为了获得更高级的功能,您需要在其上使用脚本语言(如 Lua)。其中之一是允许您读取环境变量。我在这里写了如何做到这一点:

https://docs.apitools.com/blog/2014/07/02/using-environment-variables-in-nginx-conf.html

在 Nginx 上让 Lua 工作的常规方法是使用 Openresty,这是一种已预先安装了几个模块(包括 Lua)的 Nginx 版本。您可以将 lua-resty-mysql 添加到混合中,然后直接从 Lua 中完成想做的一切。我从未使用过 lua-resty-mysql,因此无法为您编写代码。如果您打算使用 Mysql,则必须学习其文档。在这个过程中请注意 Redis,它可能比 Mysql 更适合。

2014-09-21 11:33:12
用户2782387
用户2782387

感谢您的帮助。这个方法对我不起作用,但是在经过很多努力之后,我最终成功了。如果有其他人需要,这是给其他人参考的。

事实证明,在nginx中$http_host已经被全局定义了,所以这个问题得到了解决。

        set $httphost $http_host; # 创建和初始化变量
        set $docroot "";

    # 开始LUA脚本
    rewrite_by_lua '
                    -- 确保已定义http主机
                    if not ngx.var.httphost then
                      ngx.log(ngx.ERR,"错误 - 未定义httphost")
                      return
                    end

                       -- 开始mysql
                    local mysql = require "resty.mysql"
                    local db, err = mysql:new()

                    db:set_timeout(1000) -- 1秒

                    local ok, err, errno, sqlstate = db:connect
                    {
                            host = "127.0.0.1",
                            port = 3306,
                            database = "db",
                            user = "user",
                            password = "password",
                            max_packet_size = 1024 * 1024
                    }

                    if not ok then
                      ngx.log(ngx.ERR,"MySQL连接失败: ", err, ": ", errno, " ", sqlstate)
                      return
                    end

                    -- 防止注入攻击
                    local hname = ngx.unescape_uri(client)
                    local quoted_name = ngx.quote_sql_str(hname)

                    local sql = "select docroot from users where customer =" .. quoted_name
                    result,err,errno,sqlstate = db:query(sql,1)
                    if not result then
                       ngx.log(ngx.ERR,"MySQL错误的结果: ", err, ": ", errno, ": ", sqlstate, ".")
                       return
                    end

                    if not result[1].docroot then
                      ngx.log(ngx.ERR,"MySQL错误 - 没有返回docroot")
                      return
                    end

                    ngx.var.docroot = result[1].docroot
            ';
           # 现在我们可以为此主机设置docroot
          root           /var/www/$docroot;
2014-09-22 01:24:28