私が歌川です

@utgwkk が書いている

nginxのaccess_logとerror_logのログファイル名に変数を使えるかどうか

tl;dr

access_log には変数を使えるけど制約が多い。error_log には使えない。ホスト名の数だけ server directiveを列挙した方が早そう。

nginx 1.21.1 で確認した。

変数を使えるかどうか

表題のことが気になったので調べた。部内k8sクラスタにアプリケーションをデプロイする際に、ホスト名を列挙するだけで同じようなnginxの設定を反映できるようにしたい、そしてアクセスログやエラーログをホスト名ごとに分けたい、という経緯である。つまり以下のように書けるとありがたい。

server {
  listen [::]:443 ssl http2;
  server_name host-a.example.com host-b.example.com;

  access_log /var/log/nginx/$host.access.log main;
  error_log  /var/log/nginx/$host.error.log;

  location / {
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://upstream;
  }
}

access_log

http://nginx.org/en/docs/http/ngx_http_log_module.html#access_log を見ると、ファイル名に変数を使うことができるように読める。ただし制約がいろいろある。とくに、nginxを動かすuserがログファイルの出力先ディレクトリに書き込み可能でなければならない、という制約に引っかかった。/var/log/nginx の所有者が root:root で、パーミッションが700のときに、nginxを www-data userなどで動かしているとアクセスログが出力されない。

error_log

http://nginx.org/en/docs/ngx_core_module.html#error_log を見ると access_log とは違って変数に対する言及がなく、使えなさそう。実際、先述のようなnginx.confを反映したら /var/log/nginx/$host.error.log というファイルができていた……。

最終的にどうしたか

ホスト名を列挙しておいて、ホスト名の数だけ server directiveを展開するようにした。具体的には、以下のようなitamae recipeを反映した。

node.reverse_merge!(
  nginx_hosts: %w[
    host-a.example.com
    host-b.example.com
  ],
  # 中略
)

template '/etc/nginx/conf.d/multiple-hosts.conf' do
  owner 'root'
  group 'root'
  mode '0644'
  notifies :reload, 'service[nginx]'
end

templates/etc/nginx/conf.d/multiple-hosts.conf は以下のような内容になっている。

<% node[:nginx_hosts].each do |host| -%>
server {
  listen [::]:443 ssl http2;
  server_name <%= host %>;

  access_log /var/log/nginx/<%= host %>.access.log main;
  error_log  /var/log/nginx/<%= host %>.error.log;

  location / {
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://upstream;
  }
}
<% end -%>