Hugoの動的プレビューをNginxリバプロ越しに行う設定

Hugoの動的プレビューをNginxリバプロ越しに行う設定
Page content

約1年越しの悩み

当サイト (RemoteRoom) は、Hugoという静的サイトジェネレータ (Static Site Generator) で構築している。Hugoのserver機能を併用すると、markdown記法で書き進めるコンテンツを、テンプレートが適用されたウェブサイトhttp://localhost:1313/上ですぐに動的にプレビューできるのでとても助かっている。

このプレビューを、私の環境では次のような仕掛けの上で行ってきた。

  1. Hugoのドラフトデータはどこでも編集できるようにDropboxに保存して同期。そのデータを、Dropboxデーモンが常駐しているクラウド上のLinuxサーバで常時hugo serverして動的なプレビューサイトを生成
  2. プレビューサイトの確認はTailscale越しにhttp://100.NNN.NNN.NNN:1313/で行う (つまり、Tailscale導入端末での閲覧がメイン。クローズドで安全ではあるが)

しかし、これまで2の部分が理想とは違っていた。2の理想は次の通り。

  • プレビューサイトの確認はBASIC認証をかけたhttps://hugo.example.com/でどの端末からでも行えること。かつ変更ページのlive reloadingも効くこと

2に関しては約1年前に「Nginxで行うReverse Proxyの部分で、live reloadingに用いられているwebsocket通信を通す設定がわからない」と悩んで、以降諦めていた問題であったが、今改めて調べてみると一気に解決したのでメモします。

問題がクリアできた設定

1. Hugoの起動オプション

Hugoの起動オプションは次のように設定する。通信に関する4つの appendPort, baseURL, liveReloadPort, port オプションのうち1つでも欠けるとおそらく不具合が発生する (不具合の例としては、websocket通信が1313番ポートを使用してリバプロ越しに通信できない状態になったり、プレビューサイト内のリンク先URLに:1313が含まれたり)。

hugo server \
	--appendPort=false \
	--baseURL=http://localhost/ \
	--liveReloadPort=443 \
	--navigateToChanged \
	--port=1313

なお、私の場合はプレビューという目的上、非公開中のページもレンダリングする次のオプションも追加している。

	--buildDrafts=true \
	--buildExpired=true \
	--buildFuture=true

2. Nginx (Reverse Proxy)

Reverse Proxyとして動作させるNginxのサイト設定に関しては、Websocket for LiveReload using wrong port if Hugo binds to port 80 · Issue #2205 · gohugoio/hugoコメントを参考にした。主要な内容を抜き出すと次の通り。locationで/livereloadを別扱いにしているのがポイントなのかもしれない。

server {
	listen 80;
	listen [::]:80;
	server_name hugo.example.com;
		location / {
			return 301 https://$host$request_uri;
		}
}

server {
	listen 443;
	listen [::]:443;
	server_name hugo.example.com;
		auth_basic "Restricted";
		auth_basic_user_file /etc/nginx/htpasswd.txt;
		location / {
			proxy_pass http://localhost:1313/;
			proxy_set_header Host $http_host;
			proxy_set_header X-Real-IP $remote_addr;
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
			proxy_set_header X-Forwarded-Proto $scheme;
		}
		location /livereload {
			proxy_pass http://localhost:1313;
			proxy_set_header Host $http_host;
			proxy_set_header X-Real-IP $remote_addr;
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
			proxy_set_header X-Forwarded-Proto $scheme;
			proxy_http_version 1.1;
			proxy_set_header Upgrade $http_upgrade;
			proxy_set_header Connection "Upgrade";
		}
}

参考) Twitter