shantiworks

2012.03.21

mod_rewriteで表示させたくないフォルダをリダイレクトする + mod_rewriteサンプルと正規表現

フォルダ以下のファイルは見せたいけど、フォルダにindex.html置いてないからフォルダ自体にアクセスした場合にindex ofが表示されてファイル一覧が表示されてしまうって問題。
それを回避するために、403エラーでアクセス拒否設定してた。

で、最近googleウェブマスターツールの表示がいろいろ新しくなって、エラーの項目で403エラーで拒否ってるページが{拒否されましたエラー}に数えられてることが発覚。
拒否してるんだから当然なんだけど、エラーで計測されてるのはなんだかよくなさそうだから別の方法でindex ofを表示しないように対策。

調べたところ、.htaccess に mod_rewrite 書いて中身ファイル一覧を見せたくないフォルダへのアクセスを301リダイレクトするのがよさそうってことで。

中身ファイル一覧を見せたくないフォルダへのアクセスを上位フォルダへ301リダイレクトする設定。
RewriteEngine on
RewriteRule ^(.*)/見せたくないフォルダ1/$ /$1/ [R=301]
RewriteRule ^(.*)/見せたくないフォルダ2/$ /$1/ [R=301]

.htaccessにすでにいろいろ書いてるからどこにこれを追加するかってのは、

  • 最初は、アクセス制御。
  • 次は、外部向けリダイレクト。
  • 最後は、内部でのリライト。

の順序がいいらしいから、今回の場合は最後に追加。

ちょっとつまづいたところがリダイレクト先のファイルのcssを相対パスで指定してると、cssを適用できないってのがあって絶対URLに書き換えて解決。

mod_rewrite は他にもたくさん利用用途があるみたいだから以下サンプルと使える正規表現の引用。

.htaccessファイルに複数の記述を書くときの適切な順番を尋ねる質問がWebmasterWorldに投稿された。原則的に、次のように考えるといいだろうとのことだ。

  1. 最初は、アクセス制御。
  2. 次は、外部向けリダイレクト。
  3. 最後は、内部でのリライト。

リダイレクトやリライトの記述が複数ある場合は、まず適用範囲が狭い(限定的な)ルールを先に記述し、もっとも適用範囲の広い(一般的な)ルールを後に記述する。

記述の順番が適切でないと、正しく処理されなかったり、必要のない余計なリダイレクトが入ったりすることがある。

技術的には、どの記述が先に処理されるかは、.htaccess上の記述の順番ではなくApacheモジュールの読み込み順によるということだが、おおまかには、ここで示したような順で書いておくのが良さそうだ。

引用元:?“これをやったらグーグルペナルティ”なSEO手法11選 など10+1記事(海外&国内SEO情報) (p.2) | Web担当者Forum.

/hoge/ を /fuga/ に rewrite(リダイレクト)する。

RewriteEngine on
RewriteRule ^/hoge/$ /fuga/

/hoge/ 以下を /fuga/ 以下にまとめて rewrite(リダイレクト)する。

RewriteEngine on
RewriteRule ^/hoge/(.*)$ /fuga/$1

/hoge/ 以下で末尾が .jpg のリクエストのみを /fuga/ 以下に rewrite(リダイレクト)する。

RewriteEngine on
RewriteRule ^/hoge/(.*\.jpg)$ /fuga/$1

/hoge/ 以下で末尾が .jpg か .gif のリクエストのみを /fuga/ 以下に rewrite(リダイレクト)する。

RewriteEngine on
RewriteRule ^/hoge/(.*)\.(jpg|gif)$ /fuga/$1.$2

/cgi-bin/hoge/fuga?を /cgi-bin/example.cgi?q=hoge&opt=fuga?に rewrite(リダイレクト)(いわゆる、動的アドレスを静的アドレスに変換するってやつ)

RewriteEngine on
RewriteRule ^/cgi-bin/([0-9A-Za-z]+)/([0-9A-Za-z]+)$ /cgi-bin/example.cgi?q=$1&opt=$2


リダイレクト時のブラウザのURL欄

mod_rewrite で rewrite(リダイレクト)処理を行ったとき、以下のようにサーバパスで rewrite(リダイレクト)させると、ブラウザのURL欄は書き換わらない。

RewriteEngine on
RewriteRule ^/hoge/$ /fuga/

例えば、
http://www.example.com/hoge/ にアクセスすると、
http://www.example.com/fuga/ の中身が、
URL欄は http://www.example.com/hoge/ のまま表示される。

しかし、以下の例では、リダイレクトと同時にURL欄が書き換わる。

RewriteEngine on
RewriteRule ^/hoge/$ /fuga/?[R=301]

RewriteEngine on
RewriteRule ^/hoge/$ /fuga/?[R=302]

RewriteEngine on
RewriteRule ^/hoge/$?http://www.example.com/fuga/

最後の URL にリダイレクトさせるパターンは、同じサーバ内の URL であっても、飛び先を URL で記述するとブラウザのURL欄が書き換わります
同一サーバ内であれば、URLにリダイレクトさせると無駄にログも増えるのであまりオススメしません。


%2F問題

Apache1.X 系で mod_rewrite を使う場合、URLに「%2F」が含まれると思い通りに動作しない問題があります。
(Apache2.X 系でも同様ですが、Apache2.0.46 以降では「AllowEncodedSlashes On」により回避できます。)

例えば、以下のような書き換えを記述したとします。

RewriteEngine on
RewriteRule ^/keyword/(.*)$ /cgi-bin/script.cgi?k=$1

想定としては、
http://www.example.com/keyword/hogefuga?というアクセスに対して
http://www.example.com/cgi-bin/script.cgi?k=hogefuga?の結果を返します。

hogefuga?の部分が色々と変化するわけです。

この際、
http://www.example.com/keyword/hogefuga/hage?は
http://www.example.com/cgi-bin/script.cgi?k=hogefuga/hage?となりますが、

http://www.example.com/keyword/hogefuga**%2F**hage?は
http://www.example.com/cgi-bin/script.cgi?k=hogefuga**%2F**hage?とならず、**404エラーになります**。

直接、
http://www.example.com/cgi-bin/script.cgi?k=hogefuga%2Fhage?にアクセスするとこの問題は起きません。

先にも書きましたが、Apache2.0.46 以降では httpd.conf に「AllowEncodedSlashes On」を記述することにより回避できます。
しかし、Apache1.X の環境ではなかなか回避できずにはまる要素だと思います。


アクセスを拒否する

どこかにリダイレクトするのではなく、特定のアクセスにエラーを返せます。
.htaccess へのアクセスを拒否する。

RewriteEngine On
RewriteRule \.htaccess -?[F]

/hoge/ 以下へのアクセスに 403 Forbidden を返します。

RewriteEngine On
RewriteRule ^/hoge/.*?[F]

/hage/ 以下へのアクセスに 410 Gone を返します。

RewriteEngine On
RewriteRule ^/hage/.*?[G]


複数の RewriteRule

RewriteRule は複数かけます。
/hoge/ 以下を /fuga/ 以下にリダイレクとした上に /fuga/hage/ 以下のものは /foo/ 以下にリダイレクトする。

RewriteEngine On
RewriteRule ^/hoge/(.*) /fuga/$1
RewriteRule ^/fuga/hage/(.*) /foo/$1

上の例で、/hoge/ 以下を /fuga/ 以下にリダイレクとさせた時点で処理を終わらせる、つまり次のリダイレクトを実行させないようにするには [L] を付加します

RewriteEngine On
RewriteRule ^/hoge/(.*) /fuga/$1?[L]
RewriteRule ^/fuga/hage/(.*) /foo/$1


RewriteRule のオプション

これ以外にもいろいろありますが。
HTTPステータスコードを吐く [R=ステータスコード]

RewriteEngine On
RewriteRule ^/hoge/(.*) /fuga/$1?[L,R=301]
RewriteRule ^/fuga/hage/(.*) /foo/$1

大文字、小文字を区別しない [NC]

RewriteEngine On
RewriteRule ^/hoge/(.*) /fuga/$1 [NC,L]
RewriteRule ^/fuga/hage/(.*) /foo/$1


ある条件が揃ったらリダイレクト

RewriteCond を使えば、ある条件に合致したときだけリダイレクトするということも、もちろん可能です。
HTTP_HOST が www.example.com だったら RewriteRule を適用する。

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.example.com$
RewriteRule ^/(.*) /$1

HTTP_HOST が www.example.com じゃなかったら RewriteRule を適用する。

RewriteEngine On
RewriteCond %{HTTP_HOST} !^www.example.com$
RewriteRule ^/(.*) /$1

HTTP_HOST が www.example.com で HTTP_USER_AGENT に MSIE が含まれていたら RewriteRule を適用する。

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.example.com$
RewriteCond %{HTTP_USER_AGENT} MSIE
RewriteRule ^/(.*) /$1

RewriteCond を複数並べると AND でつながっていく。OR にしたい場合は [OR] をつける

HTTP_HOST が www.example.com であるか、または HTTP_USER_AGENT に MSIE が含まれていたら RewriteRule を適用する。

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.example.com$?[OR]
RewriteCond %{HTTP_USER_AGENT} MSIE
RewriteRule ^/(.*) /$1

RewriteCond の条件で大文字、小文字を区別しない場合は [NC] をつける。

HTTP_USER_AGENT に MSIE や msie や MsIe や MSiE などが含まれていたら RewriteRule を適用する。

RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} MSIE?[NC]
RewriteRule ^/(.*) /$1

RewriteCond で対象となる変数には以下のようなものがあります。

HTTP_USER_AGENT / HTTP_REFERER / HTTP_COOKIE / HTTP_FORWARDED / HTTP_HOST / HTTP_PROXY_CONNECTION / HTTP_ACCEPT
REMOTE_ADDR / REMOTE_HOST / REMOTE_USER / REMOTE_IDENT / REQUEST_METHOD / SCRIPT_FILENAME / PATH_INFO / QUERY_STRING / AUTH_TYPE
DOCUMENT_ROOT / SERVER_ADMIN / SERVER_NAME / SERVER_ADDR / SERVER_PORT / SERVER_PROTOCOL / SERVER_SOFTWARE
TIME_YEAR / TIME_MON / TIME_DAY / TIME_HOUR / TIME_MIN / TIME_SEC / TIME_WDAY / TIME
API_VERSION / THE_REQUEST / REQUEST_URI / REQUEST_FILENAME / IS_SUBREQ

引用元: mod_rewrite サンプル集/楽.

ディレクティブ

ディレクティブと書式

初期値

説明

RewriteEngine on/off

off

書き換えの可否を設定。

RewriteOptions inherit

inherit : 現在の設定値を親ディレクトリの設定値から強制的に継承する。

RewriteBase /

/

書き換えのベースとなるパス(ベースが明白な場合は不要)。

RewriteCond テスト文字列 条件 パターン。

条件によるテスト文字列とパターンの比較。

RewriteRule パターン 置換対象。

パターンを置換対象で置き換える。

オプション

[R]

強制的にリダイレクト (Redirect) する。
[R=301] : 永久的に移動。HTTP レスポンスの「301 : Moved Permanently」を返します。。
[R=302] : 一時的な移動。HTTP レスポンスの「302 : Moved Temporarily」を返します、デフォルト。

[F]

強制的にアクセス禁止 (Forbidden) にする。
HTTP レスポンスの「403 : Forbidden」を返します。

[G]

強制的に消去済み (Gone) にする。
HTTP レスポンスの「410 : Gone」を返します。 もはや存在しないページを消去済みとしてマークします。

[L]

書き換えが行われたら終了 (Last) にする。
現在の書き換え後の URL が後続のルール によってそれ以上書き換えられることを防止します。

[NC]

パターンについて、文字の大小を区別しない(No Case)。 つまり、”A-Z” と “a-z” は区別されません。

[OR]

または。

正規表現

文字

説明

!

否定。

.

任意の1文字。

[ ]

括弧内のいずれかの文字。

[^ ]

括弧内のいずれかの文字以外。

|

または。

?

直前の文字の0回または1回の繰り返し

*

直前の文字の0回以上の繰り返し。

直前の文字の1回以上の繰り返し。

( )

選択範囲の境界を明示する、もしくは後方参照を作成する。

^

行頭。

$

行末。

$n

(0 <= n <= 9) 後方参照。 n番目の( )内の値が入ります。

%{ }

サーバ変数の取得。

\

(日本語環境では円マーク)正規表現の特殊文字をエスケープする。

サーバ変数

変数名

説明

HTTP_USER_AGENT

ブラウザの種類とバージョン。

HTTP_REFERER

参照元の URL 。

HTTP_COOKIE

設定されているクッキー情報。

HTTP_FORWARDED

プロキシサーバ情報。

HTTP_HOST

接続要求しているホスト名。

HTTP_PROXY_CONNECTION

接続先プロキシサーバとの接続状態。

HTTP_ACCEPT

ブラウザが認識可能なデータ形式。

DOCUMENT_ROOT

サイトのルートディレクトリ。

SERVER_ADMIN

サーバ管理者のメールアドレス情報。

SERVER_NAME

サーバのホスト名、ドメイン名、またはIPアドレス情報。

SERVER_ADDR

サーバのIPアドレス。

SERVER_PORT

送信に使われたサーバのポート番号。

SERVER_PROTOCOL

送信に使われたプロトコルの名前とレビジョン情報。

SERVER_SOFTWARE

起動したサーバソフトウエアの名前とバージョン情報。

REMOTE_ADDR

リモートホストのIPアドレス情報。

REMOTE_HOST

リモートホストのドメイン名。

REMOTE_USER

ユーザの認証名。

REMOTE_IDENT

リモートホストのユーザ名。

REQUEST_METHOD

リクエストを送信した方法。

REQUEST_URI

リクエストされたURI。

SCRIPT_FILENAME

現在実行しているスクリプト名。

PATH_INFO

クライアントから送られるパス情報。

QUERY_STRING

URL に付加して渡された “?” 以降の文字列。

AUTH_TYPE

ユーザを認証するときに使用する認証方法。

TIME_YEAR

サーバのシステム日付・年

TIME_MON

サーバのシステム日付・月

TIME_DAY

サーバのシステム日付・日

TIME_HOUR

サーバのシステム日付・時

TIME_MIN

サーバのシステム日付・分

TIME_SEC

サーバのシステム日付・秒

TIME_WDAY

サーバのシステム日付・曜日

TIME

サーバのシステム日付・Unix タイムスタンプ。

“.htaccess” ファイルにおける Rewrite の記述方法

一般的な書式

RewriteEngine on RewriteBase / #ドメインの統一 RewriteCond %{HTTP_HOST} ^(example\.com)(:80)? [NC] RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L] #ディレクトリの移転 RewriteRule ^old_dir(.*)$ /new_dir$1 [R=301,L] #ファイルの移転 RewriteRule ^old_dir/index\.html$ /new_dir/index.html [R=301,L] #クローラのアクセス禁止 RewriteCond %{HTTP_USER_AGENT} Badbot-1 [NC, OR] RewriteCond %{HTTP_USER_AGENT} Badbot-2 [NC] RewriteRule !^robots\.txt$ – [F] RewriteEngine off*注?書き換え対象に正規表現の特殊文字が含まれている場合は、 “\” (日本語環境では円マーク) でエスケープします。
*注?書き換え対象 “old_dir” が、 “/” から始まっていないことに注意してください。
*注?書き換え後 “/new_dir” が、 “/” から始まっていることに注意してください。

ファイルの移転

リクエストに対して、ファイルが移転したことを知らせます。

RewriteRule ^old_dir/index\.html$ /new_dir/index.html [R=301,L]【解説】(行頭から)old_dir/index.html(行末まで)のアクセスを “/new_dir/index.html” にリダイレクトし、ここではファイルが永久に移転したことを通知しています。 書き換えが行われたら終了。

ディレクトリの移転

リクエストに対して、ディレクトリ全体が移転したことを知らせます。
“http://?” から記述することにより、外部ドメインへのリダイレクトも可能です。

# 内部移転 RewriteRule ^old_dir(.*)$ /new_dir$1 [R=301,L] # 外部移転 RewriteRule ^old_dir(.*)$ http://www.example/new\_dir$1 [R=301,L]【解説】”.*” =任意の1文字0回以上の繰り返し。 (.*) の値が、後方参照 $1 に入ります。

拡張子の変更

リクエストに対して、ファイルの拡張子を書き換えてリダイレクトします。

# 拡張子が “.html” のファイルを、全て “.phtml” に変更する RewriteRule ^(.*)\.html$ /$1.phtml [R=301,L] # 特定のディレクトリに対して、ファイルの拡張子を変更する RewriteCond %{REQUEST_URI} ^/example/ [NC] RewriteRule ^(.*)\.html$ /$1.phtml [R=301,L] # 特定のディレクトリを除いて、ファイルの拡張子を変更する RewriteCond %{REQUEST_URI} !^/example/ [NC] RewriteRule ^(.*)\.html$ /$1.phtml [R=301,L]【解説】特定のディレクトリに関しては、(行頭から)”/example/” の大小を問わない文字を含む(もしくは含まない)アクセスに対して、拡張子 “.html” を “.phtml” に書き換えてリダイレクトしています。 ここではファイルが永久に移転したことを通知しています。 書き換えが行われたら終了。

サーバ移転(サイトの引越し)

リクエスト全体を、新しいドメインへリダイレクトします。

RewriteRule ^(.*)$ http://www.new-example.com/$1 [R=301,L]【解説】HTTPステータスコード “R=301(Moved Permanently)” を付加することにより、URLが永久に移動したことを検索サイトのクローラに通知します。 この処理で、旧サイトのページランクを自動的にほぼ引き継ぐことができます。
検索サイトへの反映は、クローラにもよりますが、1週間から1ヶ月ほどかかります。

ドメインの統一

サーバーは1つのドメイン、例えば “example.com” に対して、”www.example.com” でもリクエストを受け付けます。
host がサブドメインを使用している場合は、更に “example.host.com” と “www.example.host.com” でも閲覧可能になり、合計4つのサイトにアクセスが分散することになります。
これは、 SEO 対策上あまり好ましいことではありません。 ここでは、”Rewrite” を使って、”www.example.com” に統一する場合を記述します。

◇サブドメインを使用していない場合 RewriteCond %{HTTP_HOST} ^(example\.com)(:80)? [NC] RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L] ◇サブドメインを使用している場合 RewriteCond %{HTTP_HOST} ^(example\.com)(:80)? [NC,OR] RewriteCond %{HTTP_HOST} ^(example\.host\.com)(:80)? [NC,OR] RewriteCond %{HTTP_HOST} ^(www\.example\.host\.com)(:80)? [NC] RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]

アクセス制限

サーバ変数を取得して、アクセス制限を掛けます。
アクセス制限は、サーバに思わぬ負荷をかけることがあります。 不必要なアクセス制限はできるだけ掛けないようにしてください。
*注?十分にアクセス情報を解析してから設定してください。 設定によっては正当な訪問者もアクセスできなくなる可能性があります。

  • [F] は、「Forbidden(アクセス禁止)」を意味します。
  • 特殊文字の前に “\”(日本語環境では円マーク)を付加する事に注意してください。
  • “REMOTE_HOST” は、サーバーによっては取得できない場合があります。

◇特定のホストからのアクセスを全て禁止する RewriteCond %{REMOTE_HOST} ^example\.com$ [NC, OR] RewriteCond %{REMOTE_ADDR} ^192\.168\.1\. RewriteRule ^.* – [F]【解説】”REMOTE_HOST” が取得できない場合は、 “REMOTE_ADDR” を使用してアクセス制限をかけます。

◇特定のブラウザからのアクセスを全て禁止する RewriteCond %{HTTP_USER_AGENT} ^Mozilla/4\.0 \(compatible; MSIE 6\.0\)$ [NC] RewriteRule ^.* – [F] ◇特定の Referer からのアクセスを全て禁止する RewriteCond %{HTTP_REFERER} ^http://www\\.example\\.com/bad\\.html$ [NC] RewriteRule ^.* – [F] ◇特定の Referer 以外からのアクセスを全て禁止する(=特定の Referer からのみアクセスを全て許可する) RewriteCond %{HTTP_REFERER} !^http://www\\.example\\.com/good\\.html$ [NC] RewriteRule ^.* – [F] ◇直リンクを全て禁止する RewriteCond %{HTTP_REFERER} !example\.com [NC] RewriteRule ^.* – [F]【解説】Referer が “example.com” を含まないリクエストに対して、全てのアクセスを禁止します。

◇画像の直リンクを禁止する RewriteCond %{HTTP_REFERER} !example\.com [NC] RewriteRule \.(jpg|png|gif)$ – [F]【解説】Referer が “example.com” を含まないリクエストに対して、拡張子が “.jpg” または “.png” または “.gif” へのアクセスを禁止します。

◇特定のホスト & 特定のブラウザからのアクセスを禁止する RewriteCond %{REMOTE_ADDR} ^192\.168\.1\. RewriteCond %{HTTP_USER_AGENT} ^Mozilla/4\.0 \(compatible; MSIE 6\.0\)$ RewriteRule ^.* – [F] ◇特定の検索ロボット(クローラ)に対して、 “robots.txt” 以外のアクセスを禁止するクローラのアクセス禁止は、サーバの負荷を伴います。 そこで先に、ここに記述する全てのクローラを “robots.txt” で拒否しておきます。 それを無視した悪質クローラだけを、最終的にここでアクセス禁止にします。

RewriteCond %{HTTP_USER_AGENT} Badbot-1 [NC, OR] RewriteCond %{HTTP_USER_AGENT} Badbot-2 [NC, OR] RewriteCond %{HTTP_USER_AGENT} Badbot-3 [NC, OR] RewriteCond %{HTTP_USER_AGENT} Badbot-n [NC] RewriteRule !^robots\.txt$ – [F]【解説】”HTTP_USER_AGENT” が、 “Badbot-1”, から “Badbot-n” の文字(文字の大小を区別しない)を含むクローラに対して、 “robots.txt” 以外のアクセスを禁止します。

引用元:?.htaccess – Rewrite.

mod_rewriteでよく使う正規表現を例を挙げて解説していきましょう。

RewriteRule ^/blog/(.*)$ /newblog/$1

.*はあらゆる文字の0を含む任意の回数の繰り返しにマッチします。()でくくった部分は$1に代入されます。

ここで”^”は行の先頭、”$”は行の末尾を表しています。

RewriteRule ^/blog/.*/(.*)$ /newblog/$1

この例では最初の.*は()でくくられていないので、変換後の文字列には使われません。このルールはディレクトリ階層が1つ減ることになります。(/blog/2009/sample.html が /newblog/sample.htmlになります)

RewriteRule ^/blog/(2008|2009)/(.*)$ /newblog/$2

この例の(2008|2009)はグループ化するために使われています。これは変数$1に代入されますが、変換後のアドレスでは必要ないので使用されていません。

RewriteRule ^/blog/(2008|2009)/(.*)$ /newblog/$1/$2

もちろんこの例のように$1を利用することも出来ます

RewriteRule ^/blog/(20[0-9][0-9])/(.*)$ /newblog/$1/$2

[]で囲まれた表現は、使用する文字の範囲を指定します。[0-9]ならば0から9のどれかの数字1文字にマッチします。この例では2000~2099のどれかにマッチすることになります。

RewriteRule ^/blog/(20[0-9]{2})/(.*)$ /newblog/$1/$2

この例も先ほどと同じく2000~2099のどれかにマッチします。ここで{2}は、直前の表現(この場合[0-9])を2回繰り返すことを表しています。

RewriteRule ^/blog/([0-9]{4})/([a-z]*)\.html /newblog/$1/$2.shtml

この例では[0-9]{4}となっているので0000~9999のどれかにマッチします。同様に好きな回数の繰り返しを指定してやることが出来ます。 2つ目の正規表現[a-z]*はあらゆる小文字の英字列にマッチします。また、\.とピリオドの前にバックスラッシュが置かれているのはピリオドを正規表現としてではなく通常のピリオドとして扱うことを表しています。同じように、”$”, “^”, “*”などの正規表現で使われる特殊文字を通常の文字として指定したい場合は前に”\”をつけてやります。

ちなみにこの例では、ファイル名に”-”が含まれるとうまく行きません。

RewriteRule ^/blog/([0-9]{4})/([-a-z]*)\.html /newblog/$1/$2.shtml

この例のように、[-a-z]というように指定してやると”-”を含むファイルも扱うことが出来ます。このように”-”を含む文字列にマッチさせたい場合は、”-”は[]内の先頭に指定してやる必要があります。

RewriteRule ^/blog/([0-9]{4})/([-0-9a-zA-Z]*)\.html /newblog/$1/$2.shtml

この例では、任意のアルファベット、数字、”-”を含むファイル名にマッチします。

引用元: mod_rewriteまとめ(2)mod_rewriteで使う正規表現.