Apache 2.4のWelcomeページがzh-cnになる理由

 article  Comments Off on Apache 2.4のWelcomeページがzh-cnになる理由
Feb 212021
 

CentOS Stream 8のApacheで、デフォルトのトップページがzh-cnになります。
(パッケージはhttpd-2.4.37-30.module_el8.3.0+462+ba287492.0.1.x86_64)

/etc/httpd./conf.d/welcome.confで設定されている403 NOT FOUND時のページが表示されるのですが、こちらにはen-USのページも用意されているのに何故だろうと疑問でした。

$ ls -l /usr/share/httpd/noindex/index.html*
-rw-r--r-- 1 root root 4288 Jul 30  2019 /usr/share/httpd/noindex/index.html.en-US
-rw-r--r-- 1 root root 4467 Jun 14  2019 /usr/share/httpd/noindex/index.html.es-ES
-rw-r--r-- 1 root root 4006 Jun 14  2019 /usr/share/httpd/noindex/index.html.zh-CN
-rw-r--r-- 1 root root 4006 Jun 14  2019 /usr/share/httpd/noindex/index.html.zh-HK
-rw-r--r-- 1 root root 4006 Jun 14  2019 /usr/share/httpd/noindex/index.html.zh-TW

curlでトップページを表示してみるとContent-Language: zh-cnになっています。

$ curl -I http://localhost/
HTTP/1.1 403 Forbidden
Date: Sun, 21 Feb 2021 03:09:51 GMT
Server: Apache/2.4.37 (centos) OpenSSL/1.1.1g
Content-Location: index.html.zh-CN Vary: negotiate,accept-language
TCN: choice Last-Modified: Fri, 14 Jun 2019 03:37:43 GMT ETag: "fa6-58b405e7d6fc0;5bbe58cb80a25" Accept-Ranges: bytes
Content-Length: 4006 Content-Type: text/html; charset=UTF-8
Content-Language: zh-cn

Apache公式ドキュメントにきちんと回答がありました。
https://httpd.apache.org/docs/2.4/ja/content-negotiation.html#methods

「Apache ネゴシエーションアルゴリズム」の以下の部分です。

  1. 内容の最も短い variant を選びます。
  2. 残っている variant の最初のものを選びます。 タイプマップファイルの最初にリストされているか、 variant がディレクトリから最初に読み込まれる時に ASCII順でソートしてファイル名が先頭になったか、のどちらかです。

なるほどです。先のファイルリストをみると確かにzh-*のファイルサイズは4006バイトとen-USやes-ESより小さく、かつzh-CNがファイルリストの先頭にきます。

試しにindex.html.zh-CNのファイルサイズをちょっと増やしてみると、次点のzh-HKに切り替わることが確認できます。

$ sudo sh -c "echo 1 >> /usr/share/httpd/noindex/index.html.zh-CN"
$ ls -l /usr/share/httpd/noindex/index.html.zh-*
-rw-r--r-- 1 root root 4008 Feb 21 12:28 /usr/share/httpd/noindex/index.html.zh-CN
-rw-r--r-- 1 root root 4006 Jun 14  2019 /usr/share/httpd/noindex/index.html.zh-HK
-rw-r--r-- 1 root root 4006 Jun 14  2019 /usr/share/httpd/noindex/index.html.zh-TW
$ curl -I http://localhost/
HTTP/1.1 403 Forbidden
Date: Mon, 21 Feb 2021 03:29:02 GMT
Server: Apache/2.4.37 (centos) OpenSSL/1.1.1g
Content-Location: index.html.zh-HK
Vary: negotiate,accept-language
TCN: choice
Last-Modified: Fri, 14 Jun 2019 03:37:43 GMT
ETag: "fa6-58b405e7d6fc0;5bbe41920b7b6"
Accept-Ranges: bytes
Content-Length: 4006
Content-Type: text/html; charset=UTF-8
Content-Language: zh-hk

mod_auth_kerbでgss_accept_sec_context() failed

 article  Comments Off on mod_auth_kerbでgss_accept_sec_context() failed
Jun 052010
 

Subversionリポジトリへのhttpsアクセス用に、mod_auth_kerbを使ってActive DirectoryのアカウントでのBasic認証を仕掛けたところ、認証要求が返ってこない(WWW-Authenticateヘッダーが返されない)事象に遭遇。
非SSLでのアクセスの場合はきちんと動作する。
Subversionではない、通常のコンテンツに対するhttpsアクセスも問題なし。
モジュールの組み合わせとして整理してみるとこんな感じか?

  • mod_auth_kerb + mod_ssl => OK
  • mod_auth_kerb + authz_svn => OK
  • mod_auth_kerb + authz_svn + mod_ssl => NG

失敗時は/var/log/httpd/ssl_error.logには以下のようなエラーが記録される。

gss_acquire_cred() failed: Unspecified GSS failure.  Minor code may provide more information (No such file or directory)

キャプチャを仕掛けるとそもそもKerberosサーバーに通信にいく気配もない。WWW-Authenticateヘッダーも返ってこないのだから当たり前だが。

はっきりとした原因はわからないが、

KrbMethodNegotiate off

を設定したところ正常に動作するようになった。

Kerberos V4でなにかしら動こうとしていたのだろうか。謎だ 😕

削除してしまったSSL秘密鍵をhttpdプロセスから復元

 article  Comments Off on 削除してしまったSSL秘密鍵をhttpdプロセスから復元
Sep 212009
 

[Apache-Users 7417] 誤消去してしまった秘密鍵の復元
から始まるスレッドでの話題です。
そんなの無理だろうと思っていたら、gdbでhttpdプロセスにcore吐かせて、その中に秘密鍵らしき部分をみつけたとのこと。

mod_jkでのsticky_session

 article  Comments Off on mod_jkでのsticky_session
Nov 042008
 

mod_jkでlbワーカを使う場合、セッションによって振り分け先を固定化するためにsticky_sessionという属性が用意されている(デフォルトtrue)。実際のところ、どういう動きになるのかソースを追ってみた。

sticky_sessionパラメータを参照しているのは、jk/native/common/jk_lb_worker.cのJK_METHOD service()部分のここらへん。

    if (p->worker->sticky_session) {
        /* Use sessionid only if sticky_session is
         * defined for this load balancer
         */
        sessionid = get_sessionid(s, p->worker, l);
    }

get_sessionid()もjk_lb_worker.cで実装されていて、以下のようになっている。

    val = get_path_param(s, p->session_path);
    if (!val) {
        val = get_cookie(s, p->session_cookie);
    }

URLパスからsession_path入手を試み、ダメならsession_cookieから値を設定している。
この時点でURLパスに含まれるsession_path値のほうがsession_cookieよりも優先されることが判明。

ちなみにget_path_param()もget_cookie()もjk_lb_worker.cで実装されていて、get_path_param()のほうはURLパスからp->session_pathで始まる値の”=”以降、終端(?か;か\0)までを返すようになっている。get_cookie()も似たような処理なので割愛。

次にget_sessionid()で入手したsessionidは

rec = get_most_suitable_worker(s, p->worker, sessionid, p->states, l);

で一致するsessionidを探し、なければfind_best_worker()でワーカを決定するようになっている。

なんとなく動きはわかったものの、JSESSIONIDという文字列がどこにも出現しないので、今度はそちらを追いかけてみることに。
JSESSIONIDはjk/native/common/jk_global.hの中でJK_SESSION_IDENTIFIERとして定義されている。

JK_SESSION_IDENTIFIERを参照してるのはjk_lb_worker.cのjk_get_lb_session_cookie()呼び出し部分。

    strncpy(p->session_cookie,
            jk_get_lb_session_cookie(props, p->name, JK_SESSION_IDENTIFIER),
            JK_SHM_STR_SIZ);
    strncpy(p->session_path,
            jk_get_lb_session_path(props, p->name, JK_PATH_SESSION_IDENTIFIER),
            JK_SHM_STR_SIZ);

jk_get_lb_session_cookie()はjk/native/common/jk_util.cで定義されていて、JK_SESSION_IDENTIFIERはjk_map_get_string()にそのまま渡している。

jk_map_get_string()は、結局MAKE_WORKER_PARAM(SESSION_COOKIE_OF_WORKER)マクロでworker.ワーカ名.session_cookieの設定値(デフォルト”JSESSIONID”)を返すようになっていた。

jk_get_lb_session_path()もほぼ同じでMAKE_WORKER_PARAM(SESSION_PATH_OF_WORKER)によりworker.ワーカ名.session_path設定値(デフォルト”;jsessionid”)を返す。

結局のところ、こちらは両方ともworker.propertiesでの設定値かデフォルト値かを設定しているだけ。

ここで設定されたキー(p->session_path=”;jsessionid”かp->session_cookie=”JSESSIONID”)をベースに最初に出てきたget_most_suitable_worker()で振り分け先を決定している、ということになる。

Dec 102007
 

Red Hat系Linuxにはmod_sslパッケージにcertwatchというユーティリティが含まれていて、SSL証明書の期限切れをメールで通知するようになっている。
こちらの通知を何日前からおこなうか(デフォルト30日)、またメール通知先をどこにするかは、/etc/sysconfig/httpdにCERTWATCH_OPTSを指定することで設定できる。

CERTWATCH_OPTS="-p 60 -a root@example.jp"

-pは期限、-aは通知先メールアドレスの指定で、メールアドレスを指定しないと標準出力に出力される(なのでデフォルトはrootユーザにcron結果として通知される)。

certwatchによるチェックを無効化したい場合は、

NOCERTWATCH=yes

とすればよい。

mod_rewriteで期間指定のリダイレクト

 article  Comments Off on mod_rewriteで期間指定のリダイレクト
Dec 012007
 

Apacheのmod_rewriteではRewriteCondの判定に日付や時間を使うことができます(TIME_*変数)。
これを使うとある期間限定でのリダイレクト設定を施すことが可能です。

たとえば年末年始を休暇中のページにする。

RewriteCond %{TIME_YEAR}%{TIME_MON}%{TIME_DAY} >20071228
RewriteCond %{TIME_YEAR}%{TIME_MON}%{TIME_DAY} <20080104
RewriteRule ^/index\.html /vacation.html [R,L]

上の例では2007年12月29日から2008年1月3日の間、/index.htmlへのアクセスが/vacation.htmlにリダイレクトされます。ちなみに比較演算子には">="や"<="は使えません。 TIME_HOURやTIME_MINを使えば時間帯を指定することもできます。夜間はリダイレクトするといった設定も。

RewriteCond %{TIME_HOUR}%{TIME_MIN} >1800 [OR]
RewriteCond %{TIME_HOUR}%{TIME_MIN} <0900
RewriteRule ^/index\.html /sleep.html [R,L]

条件へのマッチ状況はRewriteLogLevel 4以上でチェックできますので、そちらでご確認ください。

詳しくはApache公式ドキュメントをどうぞ。
http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html

Aug 032007
 

mod_rewriteのRewriteCondディレクティブ。内部的にはRewriteRuleのあとに判定されます。
たとえばhttp接続してきたものをhttpsにリダイレクトするようなルールを書いたとします。

RewriteEngine on
RewriteLog logs/rewrite_log
RewriteLogLevel 4
RewriteCond %{HTTPS} off
RewriteRule . https://%{HTTP_HOST}/%{REQUEST_URI} [L]

サイトがwww.example.jpだったとして、http://www.example.jp/index.htmlにアクセスしてみると、RewriteLogには以下のようなログが出力されます。

(2) init rewrite engine with requested uri /index.html
(3) applying pattern '.' to uri '/index.html'
(4) RewriteCond: input='off' pattern='off' => matched
(2) rewrite /index.html -> https://www.example.jp/index.html
(2) explicitly forcing redirect with https://www.example.jp/index.html

2行目でRewriteRuleが判定され、3行目でRewriteCondが判定されていることになります。
先頭の()数字はRewriteLogLevelを表しているのでRewriteLogLevel 4にしたのですね。

で、こちらの処理順序ですが、こちらのメーリングリストで知りました。
RE: [users@httpd] RE: case insensitive rewrite rules and nested mapping
こちらのスレッドの最後のメールで

The order of processing is
rule-pattern –> condition(s) –> rule-substitution

と説明されていました。
ま、こんな内部的な順番知っててもしょうがないかもしれませんけど 😛

Jun 282007
 

mod_jkを使ってApacheとTomcatを連携される際、Tomcat側で処理させるURLパスをJkMountディレクティブで指定しますが、開発環境など変更が激しい環境ではこの定義変更にApache再起動が必要になってしまうので不便なときがあります。

httpd.conf

JkMount /jsp-examples/* ajp13
JkMount /servlets-examples/* ajp13

これをApache再起動なしで変更したい場合は、uriworkermap.propertiesを使って定義を外だしにしておくと便利です。

httpd.conf

JkMountFile conf/uriworkermap.properties 
JkMountFileReload 60 

uriworkermap.properties

/jsp-examples/*=ajp13
/servlets-examples/*=ajp13

こうしておくとuriworkermap.propertiesを書き換えた60秒後には変更が反映されることになります。
JkMountFileReloadが再読み込みの間隔で、デフォルトは60秒。0を指定すると無効化できます。
mod_jk 1.2.20以降で利用できます。

本番では無用なミスを避けるためにも、JkMountを使うか、JkMountFileReload 0にしておくことをお勧めしますが 😛

May 302007
 

Apache 2.0 の新機能の概要 – Apache HTTP サーバより。

mod_proxy
proxy モジュールは新しいフィルタの機構を利用するためと、 より信頼できる、HTTP/1.1 に準拠した proxy を実装するために 完全に書き直されました。さらに、新しい <Proxy> 設定セクションがproxy されるサイトのより読みやすく (内部的にもより速い) 設定を提供します

知りませんでした。

ProxyPass * http://localhost:8080/

と書くよりも

<Proxy *>
  ProxyPass http://localhost:8080/
</Proxy>

としておいたほうがいいんですね、きっと。

May 292007
 

TomcatのウェブフロントエンドにApacheを使っている場合、Tomcatの出力結果に対してApacheのSSI処理を施すことができます(Tomcatの、ではなく)。

例えば

JkMount /jsp-examples/* ajp13
<Location /jsp-examples>
  SetOutputFilter INCLUDES
</Location>

とした場合、jsp-examplpes配下のjspファイルにSSIを仕込むことができます。
AddOutputFilterだとファイル拡張子の指定が必要になってしまうので、SetOutputFilterを使うのがポイントです。試してませんがAddOutputFilterByTypeでも大丈夫かも知れません。

以下、jsp-examples/snp/snoop.jspに仕込んで試したコードです。

$ diff -u snoop.jsp.orig snoop.jsp
--- snoop.jsp.orig      2007-03-06 00:26:05.000000000 +0900
+++ snoop.jsp   2007-05-29 17:02:50.000000000 +0900
@@ -52,5 +52,9 @@
 The browser you are using is <% out.print(util.HTMLFilter.filter(request.getHeader("User-Agent"))); %>
 <hr>
 </font>
+<pre>
+<!--#printenv -->
+</pre>
 </body>
+<!--#include virtual="/footer.html" -->
 </html>

virtualの場合ApacheのDocumentRootからのパスになります。fileのときは試してません 😛