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で書くことで可搬性がかなり向上します。
準備
外部ファイルを保存する場所を作る。
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で片付くので、本当にシンプルでいい。
参考資料