nginx で lua を使う
インストールと準備
deiban の場合は次で一発で終わる。
sudo apt install libnginx-mod-http-lua
最初に第一歩
location ~ / { default_type 'text/html'; content_by_lua "ngx.say('Hello, ngx_lua World!')"; }
アクセスしてみる。
lua の実行結果が表示される。
もっと他の例
nginx で lua を使ってハローワールド(ソースを直接に記述)
location /hello { content_by_lua ' ngx.print("hello-") ngx.say("world") '; }
say( ) と print() がある。改行の違いがある say は改行付き。改行で "hello\n"
とできない。sayを使う。
バージョン確認
location /lua_version{ content_by_lua 'ngx.say(_VERSION)'; }
リクエストメソッドを見る。
location /method {
content_by_lua '
ngx.print(ngx.req.get_method())
';
}
if 文を使う。
location /info { content_by_lua ' m = ngx.req.get_method() if m == "GET" then ngx.print("we got GET request") elseif m == "POST" then ngx.print("we got POST request") else ngx.print("we got OTHER request") end '; }
テストする
curl http://127.0.0.1/info > we got GET request curl -X POST -d name http://127.0.0.1/info > we got POST request curl -X DELETE http://127.0.0.1/info > we got OTHER requestt
ここまでで、if 文とHTTP メソッドの切り分け、そしてコンテンツの返し方がわかった。
ヘッダ書き出し
ヘッダの書き出し(リダイレクト)
https://github.com/openresty/lua-nginx-module#ngxredirect
location /info { content_by_lua ' m = ngx.req.get_method() if m == "POST" then return ngx.redirect("/foo", ngx.HTTP_MOVED_TEMPORARILY) end '; }
ステータスコードを変える 404 にする
location /info { content_by_lua ' m = ngx.req.get_method() if m == "POST" then ngx.status = 404 ngx.print("not found.") return; end '; }
POSTの中身にアクセス。
https://github.com/openresty/lua-nginx-module#ngxreqget_post_args
location /info { content_by_lua ' m = ngx.req.get_method() if m == "POST" then ngx.req.read_body() local args, err = ngx.req.get_post_args() if err == "truncated" then -- one can choose to ignore or reject the current request here end if not args then ngx.say("failed to get post args: ", err) return end for key, val in pairs(args) do if type(val) == "table" then ngx.say(key, ": ", table.concat(val, ", ")) else ngx.say(key, ": ", val) end end end '; }
エラー処理が多くてわかりにくい.、コア部分だけを書くと、次のようになる。
ngx.req.read_body() local args, err = ngx.req.get_post_args() key="input_name" val=args[key] if val then ngx.say( key, ": ",val) end
コマンドの実行結果
適当なコマンドを実行して、結果をブラウザに返す。
content_by_lua ' local handle = io.popen("echo hello world") local ret = handle:read("*a") ngx.say( "ret : ", ret ) return ; ';
luaにない機能を手早くつかうには、コマンドを呼び出したほうが早いから。
ただし、ユーザーのリクエスト(Cookieなどヘッダも含む)をつ勝ったコマンドのインジェクションには十分に注意すること。
リダイレクト
location /login { if ($request_method != POST) { return 302 $scheme://$host/auth.html; } if ($request_method = POST) { content_by_lua ' -- なにか処理 ngx.header["Set-Cookie"] = { string.format("hash=%s; path=/; Expires=%s", hash, expires), string.format("key=%s; path=/; Expires=%s", rand, expires), } ngx.status=302 else ngx.status=401 end return ngx.redirect("/?"..ngx.var.query_string) } }
乱数の使い方。
シードが同じなら、同じ乱数が返される。
math.randomseed( tonumber("4a4",16) ) s = "" for i = 64,1,-1 do s = s..(string.format("%x",math.random(0,15))) end print(s)
random と hash の cookie の値を一つにする
lua から nginx 変数をセットする、かつ外部ファイルにする。
lua とnginxは変数を共有することができるのです。
また、Luaは外部ファイルに記述が可能、外部Luaライブラリ・外部Luaファイルを使えば、nginxの設定ファイルから切り離して使い回しができる。
nginx の設定を抽象化してプログラミングっぽくLuaで書くことで可搬性がかなり向上します。
準備
外部ファイルを保存する場所を作る。
## nginx の起動時のディレクトリは /usr/share/nginx/ なので mkdir -p /etc/nginx/lua sudo ln -sr /etc/nginx/lua /usr/share/nginx/
server in nginx.conf
location ~ / { default_type 'text/html'; set_by_lua_file $greeting 'lua/hello.lua'; return 200 'var from lua = "$greeting"'; }
lua ファイル /etc/nginx/lua/hello.lua ( nginx からは/usr/share/nginx/lua/hello.luaとして見えている)
return 'Hello from lua file'
実行すると
まとめ
lua を使って nginx の痒いところに手が届く
## コンテンツを帰す場合 content_by_lua "ngx.say('Hello, ngx_lua World!')"; content_by_lua_file "lua/content.lua; ## 変数をセットする場合 set_by_lua var_name 'return var_value'; set_by_lua_file $greeting 'lua/hello.lua';
これで、「動的に中身を変えた変数」を作ることが出来て、nginx の設定ファイルの中に固定値で設定を書く必要がなくなり、lua スクリプトから変数を自在に設定することができる。
リバプロ先を考えるとき、サーバーの設定を変えずに済むわけである。またCookieなどのcredentials をスタティックに書く必要がなくなり、nginx の設定にパスワード類が記載されないようになる。そのため「余計なものを持たない」ことになり、管理が向上しセキュリティ向上(セキュア)になるという算段である。
nginx再起動は必要か?
再起動の実行は不要だが、リロードは必要。つまり実質的に再起動は必須といえる。
nginx は lua のコンテンツをファイルの中身から読み取ってロードして保持しているので、都度都度ファイルからは読まない。
php とどっちがいいの
本当にちょっとしたことをするくらいなら lua
で書いちゃうのがありだと思う。ログインチェックとかヘッダ追加とか。
たとえば、APIを他人に使わせないBearerで固定キー認証くらいならlua で書いてしまえばnginx+luaで片付くので、本当にシンプルでいい。