LoginSignup
1
2

More than 1 year has passed since last update.

OpenResty+Luaでコンテンツを時限公開する

Last updated at Posted at 2023-02-09

OpenResty + Luaを使うと、nginx単体ではできそうでできなかった細かな条件分けを構築することができます。
私が一番苦労したのは、静的コンテンツを時限公開することでした。

時刻で条件分けする

nginx.conf
  location /hoge {
    default_type text/html;
    content_by_lua_block {
-- 1675756800 = 2023/02/07 17:00:00
      if (os.time() < 1675756800) then
        ngx.say("このコンテンツは公開中です")
      else
        ngx.say("このコンテンツは非公開です")
      end
      ngx.say(ngx.localtime())
      ngx.say(os.time())
    }
  }

結果

$ curl xxx.xxx.xxx.xxx/hoge
このコンテンツは公開中です
2023-02-07 16:59:27
1675756767
$ curl xxx.xxx.xxx.xxx/hoge
このコンテンツは非公開です
2023-02-07 17:02:25
1675756945

時刻でステータスコードをつける

nginx.status = は ngx.say()の前にないと動きません。
これはハマりどころでしたが、HTTPのレスポンスの構造を考えると納得ではあります。

nginx.conf
  location /hoge {
    default_type text/html;
    content_by_lua_block {
      if (os.time() < 1675756800) then
        ngx.status = ngx.OK
        ngx.say("このコンテンツは公開中です")
      else
        ngx.status = ngx.HTTP_FORBIDDEN
        ngx.say("このコンテンツは非公開です")
      end
      ngx.say(ngx.localtime())
      ngx.say(os.time())
    }
  }

結果

nginx.conf側の時刻をいじってテストしました。

$ curl -vvv "xxx.xxx.xxx.xxx/hoge"
*   Trying xxx.xxx.xxx.xxx...
* TCP_NODELAY set
* Connected to xxx.xxx.xxx.xxx (xxx.xxx.xxx.xxx) port 80 (#0)
> GET /hoge HTTP/1.1
> Host: xxx.xxx.xxx.xxx
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: openresty
< Date: Tue, 07 Feb 2023 08:56:37 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
< Vary: Accept-Encoding
< Cache-Control: no-cache
<
このコンテンツは公開中です
2023-02-07 17:56:37
1675760197
* Connection #0 to host xxx.xxx.xxx.xxx left intact

$ curl -vvv "xxx.xxx.xxx.xxx/hoge"
*   Trying xxx.xxx.xxx.xxx...
* TCP_NODELAY set
* Connected to xxx.xxx.xxx.xxx (xxx.xxx.xxx.xxx) port 80 (#0)
> GET /hoge HTTP/1.1
> Host: xxx.xxx.xxx.xxx
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< Server: openresty
< Date: Tue, 07 Feb 2023 08:56:57 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
< Vary: Accept-Encoding
<
このコンテンツは非公開です
2023-02-07 17:56:57
1675760217
* Connection #0 to host xxx.xxx.xxx.xxx left intact

時刻でリダイレクトする

ngx.redirect で可能です。オプションをつけないと302リダイレクトされます。
301リダイレクトする場合には、それがキャッシュされることに気を付けてください。
公開前URLが露出したり、公開URLが再利用される環境で実装すると、一部ユーザーが、本来の公開時刻が過ぎてもページを閲覧できない可能性があります。
https://github.com/openresty/lua-nginx-module#ngxredirect

nginx.conf
  location /hoge {
    default_type text/html;
    content_by_lua_block {
      if (os.time() < 1675756800) then
        ngx.status = ngx.OK
        ngx.say("このコンテンツは公開中です")
      else
        return ngx.redirect("http://example.com")
      end
      ngx.say(ngx.localtime())
      ngx.say(os.time())
    }
  }

結果

リダイレクト側のみテストします。

$ curl -v "xxx.xxx.xxx.xxx/hoge"
*   Trying xxx.xxx.xxx.xxx...
* TCP_NODELAY set
* Connected to xxx.xxx.xxx.xxx (xxx.xxx.xxx.xxx) port 80 (#0)
> GET /hoge HTTP/1.1
> Host: xxx.xxx.xxx.xxx
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 302 Moved Temporarily
< Server: openresty
< Date: Tue, 07 Feb 2023 09:03:26 GMT
< Content-Type: text/html
< Content-Length: 142
< Connection: keep-alive
< Location: http://example.com
< Cache-Control: no-cache
<
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>openresty</center>
</body>
</html>
* Connection #0 to host xxx.xxx.xxx.xxx left intact

時限公開 + プロキシ

luaでレスポンスを生成する場合はcontent_by_lua_block で処理をフックできますが、レスポンスがプロキシから生成される場合、その前段階、 rewrite_by_lua_block で対応する必要があります。
ここもハマりどころです。
https://github.com/openresty/lua-nginx-module#directives の下部、Order of Lua Nginx Module Directives図が参考になります。

nginx.conf
  location /hoge {
    default_type text/html;
    rewrite_by_lua_block {
      if (os.time() < 1675760400) then
        ngx.exit(ngx.HTTP_FORBIDDEN)
      end
    }
    proxy_pass https://example.com/;
  }

結果

exitされる場合

OpenResty標準の403が返ってきます。

$ curl -v "xxx.xxx.xxx.xxx/hoge"
*   Trying xxx.xxx.xxx.xxx...
* TCP_NODELAY set
* Connected to xxx.xxx.xxx.xxx (xxx.xxx.xxx.xxx) port 80 (#0)
> GET /hoge HTTP/1.1
> Host: xxx.xxx.xxx.xxx
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< Server: openresty
< Date: Tue, 07 Feb 2023 09:37:24 GMT
< Content-Type: text/html
< Content-Length: 150
< Connection: keep-alive
<
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>openresty</center>
</body>
</html>
* Connection #0 to host xxx.xxx.xxx.xxx left intact

exitされずプロキシされた場合

proxy_pass先の処理が戻ってきます。

$ curl --head -v "xxx.xxx.xxx.xxx/hoge"
*   Trying xxx.xxx.xxx.xxx...
* TCP_NODELAY set
* Connected to xxx.xxx.xxx.xxx (xxx.xxx.xxx.xxx) port 80 (#0)
> HEAD /hoge HTTP/1.1
> Host: xxx.xxx.xxx.xxx
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Server: openresty
Server: openresty
< Date: Tue, 07 Feb 2023 09:31:53 GMT
Date: Tue, 07 Feb 2023 09:31:53 GMT
< Content-Type: text/html; charset=UTF-8
Content-Type: text/html; charset=UTF-8
< Connection: keep-alive
Connection: keep-alive
< Vary: Accept-Encoding
Vary: Accept-Encoding
....
< Set-Cookie: status=guest; path=/; domain=.example.com
Set-Cookie: status=guest; path=/; domain=.example.com
< Set-Cookie: v2=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=.example.com
Set-Cookie: v2=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=.example.com
...
<
* Connection #0 to host xxx.xxx.xxx.xxx left intact

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2