今日の戯言 by maa

基本的にただの独り言です。有益な情報を求めてはいけませんw



2025年04月20日 小学校の授業公開の日 [長年日記]

_ Debian Webサーバ(apache2)のアクセス制御

「はじめてのプログラミング」の授業用に Web コンテンツを用意しているのだが、学内アクセス専用にしたいために学内ローカルアドレス(http://maa.u.icc.ac.jp/pb/)で公開していたところ、学生からアクセスできないといわれた。どうやら学生が使う学内 Wi-Fi の LAN から研究室の LAN には直接アクセスできないように VLAN が設定されているようだ。こうなると proxypass の設定で大学 Web ページ下に見せているグローバルアドレス(https://www.icc.ac.jp/maa/pb/)でアクセスしてもらうしかない。何とかならないものかと研究室の Web サーバ apache2 をあれこれやってみた記録である。

mod_remoteip でクライアント IP アドレスを得る

上位サーバの proxypass 下でアクセスされると、クライアント IP アドレス(http の環境変数REMOTE_ADDR)が上位サーバの IP アドレスで記録されてしまうので、実際のクライアント IP アドレスがわからない。そこで、mod_remoteip をロードして /etc/apache2/conf-available/remoteip.conf を設定した(#a2enconf remoteip を忘れずに)。

RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 127.0.0.1
RemoteIPInternalProxy 172.16.0.0/12
RemoteIPInternalProxy 192.168.0.0/16

127.0.0.1 はなんか多くの AI クローラーが騙ってくるので、それを弾く(本来のクライアントグローバルアドレスに書き換える)ために付け加えた。172* と 192* は学内で使われているローカルアドレスである。これで環境変数 REMOTE_ADDR には本来のクライアント IP アドレスが記録される。

学内 LAN 以外からの proxypass 経由のアクセスに認証をかける

これが結構難儀した。<If> ディレクティブを使って 172.16.0.0/12 以外に認証をかけようとしたのだが、REMOTE_ADDR との文字列比較に 172.16.0.0/12 とネットワークアドレスで書けないので、純粋な文字列パターンで 172.16~172.31 に恐らく正規表現でマッチさせなければならない。そこであれこれ調べたところ、正規表現での比較には「=~」で正規表現にマッチするもの、「!~」正規表現にマッチしないものが書けるということ。また、apache2 での正規表現は perl の書き方で書くということだった。で付け加えたところは以下の <If> から </If> のところ。

<Directory "/var/www/pb">
  AllowOverride None
  Options ExecCGI
  <If "%{REMOTE_ADDR} !~ /^172\.(1[6-9]|2[0-9]|3[0-1])\..*/">
    AuthType Basic
    AuthName "pb"
    AuthBasicProvider file
    AuthUserFile "/etc/apache2/xxxxxxxxx"
    Require user userxx1 userxx2
  </If>
  <Files "*.txt*">
    Require all denied
  </Files>
</Directory>

動作チェック済みだが、マッチングパターンに漏れはないだろうか。仮に漏れがあっても情報漏洩とかするやつではないのでそこまで気に病むことでもないのだが、正規表現は強力だけどややこしい...

追記:"|" による or は3つ並べられないみたい(エラーは出ないが)だったので、"()" によりグループ化するように修正した。ようは "A | B | C" とはかけないので "(A | B) | C" のようにした。 ←動作チェックしてダメだったからこのような修正をしたのだが、or で3つ並べてもよいみたい。なんか他のところで引っかかってたのか... 結局もっともシンプルな表現で良いようだ。