Apache 2.0/1.3系及びCentOSでのApache Killer対策

DoSの脆弱性を修正した Apache 2.2.20 が公開されました。

DoSの脆弱性を修正した「Apache 2.2.20」、公開
http://www.atmarkit.co.jp/news/201108/31/apache.html

ただし、Apache 2.0系と1.3系及びCentOSのyumで導入できるApache2.2.3については、まだ修正版がリリースされていないので、以下の方法による対策が必要となります。

また、Apache 1.3系については今後も修正版はリリースされません。2.0系または2.2系へのアップデートが推奨されています。

Advisory: Range header DoS vulnerability Apache HTTPD 1.3/2.x (CVE-2011-3192)より

Apache 2.2系での対策

httpd.confに以下の行を追加して、Apacheを再起動します。

# Drop the Range header when more than 5 ranges.
# CVE-2011-3192
SetEnvIf Range (?:,.*?){5,5} bad-range=1
RequestHeader unset Range env=bad-range

# We always drop Request-Range; as this is a legacy
# dating back to MSIE3 and Netscape 2 and 3.
RequestHeader unset Request-Range

Apache 2.0/1.3系での対策

httpd.confに以下の行を追加して、Apacheを再起動します。

# Reject request when more than 5 ranges in the Range: header.
# CVE-2011-3192
#
RewriteEngine on
RewriteCond %{HTTP:range} !(bytes=[^,]+(,[^,]+){0,4}$|^$)
# RewriteCond %{HTTP:request-range} !(bytes=[^,]+(?:,[^,]+){0,4}$|^$)
RewriteRule .* – [F]

# We always drop Request-Range; as this is a legacy
# dating back to MSIE3 and Netscape 2 and 3.
RequestHeader unset Request-Range


Apacheチューニング MaxClientsの適正値

最低限やっておくといいApacheチューニング」で説明を省いたMaxClientsの適正値(preforkを対象)について書きたいと思います。

まずは、MaxClientsの適正値を考えるために必要となる各情報を調べます。

総メモリ量とシステム全体の消費メモリ量をチェック

$ free -m

上記コマンドを実行した時の「Mem:」のtotalが総メモリ量、「-/+ buffers/cache:」のusedがシステム全体の消費メモリ量となります。システム高速化のために確保されているbuffersとcacheは除外して考えてよいため、消費メモリは「Mem:」でなく、「-/+ buffers/cache:」の方を参照します。

減り続けるメモリ残量! 果たしてその原因は!? – @IT

Apache 1プロセスあたりの消費メモリ量をチェック

$ ps -ylC httpd –sort:rss

上記コマンドを実行した時のRSSが各Apacheプロセスの消費メモリ量(KB)となります。プロセスごとにバラつきがあるので、平均値を算出します。

MaxClientsに設定してもいい最大値を算出

ここまで調べた情報をもとにMaxClientsに設定してもいい最大値を算出します。計算式は以下のとおりです。

MaxClients最大値 = (総メモリ量 – システム全体の消費メモリ量)/(Apache 1プロセスあたりの消費メモリ量)

例えば、総メモリ量が「1002MB」、システム全体の消費メモリ量が「164MB」、Apache 1プロセスあたりの消費メモリ量が「10MB」であれば、MaxClientsに設定してもいい最大値は「83」となります。この場合、少し余裕を見て50〜70で設定するとよいかと思います。

その他、StartServersなどの数値はとりあえず標準のままでも構いません。MaxRequestsPerChildだけは1000くらいにした方がいいかもです。


簡単にできるWebサーバの負荷軽減

先日書いた「最低限やっておくといいApacheチューニング」の補足として、Webサーバの負荷軽減について、簡単にできることだけ紹介したいと思います。

  • サーバ全体の負荷を減らす
  • キャッシュを利用する
  • httpdの1プロセスあたりの負荷を減らす
  • HTTPリクエストを減らす

サーバ全体の負荷を減らす

基本中の基本です。Webサーバとして不要なプロセスを停止させることで、サーバ全体の負荷を減らします。さくらVPSとかだと、最初から不要なプロセスはほとんど停止されているので、あまり気にしなくてもいいかと思います。

一からインストールする場合は、以下のページがすごく参考になります。

キャッシュを利用する

キャッシュを活用すれば、Webページの読み込みが速くなるだけでなく、サーバの負荷も軽減できます。PHPを使っているならAPCがベストです。APCの導入方法は「さくらVPSでWebサーバを構築するテンプレ」を参考にしてください。「pecl install APC」で入れると面倒なので「yum install php-pecl-apc」の方をオススメします。

他にもプログラム側でPEAR:Cache_Liteとかを活用するといいかと思います。

httpd(Apache)の1プロセスあたりの負荷を減らす

Apacheの不要なモジュールの読み込みを停止することで、Apache1プロセスあたりの負荷を減らします。例えばメモリ消費を1プロセスで数MB減らせれば、100Client時に全体で数百MB減らしたことになります。設定は「最低限やっておくといいApacheチューニング」を参考にしてください。

HTTPリクエストを減らす

Expiresの設定

画像やFlash、CSS、JSなど、ほとんど変更しないコンテンツのブラウザキャッシュ期間を長くすることで、HTTPリクエストを減らします。設定は「最低限やっておくといいApacheチューニング」を参考にしてください。

画像やJavaScript、CSSを別のサーバに切り出す

別途サーバを借りて、画像やJavaScript、CSSをそちらに配置すれば、HTTPリクエストをかなり減らすことができます。サブドメインを使って、resources.xxx.com/images/hogehoge.png とか、resources.xxx.com/js/fugafuga.jsとかやるといいと思います。

その他

.htaccessを使わない

.htaccessを使うとだいぶ遅くなるので、.htaccessを使わずにhttpd.confを使った方がいいです。1.2〜1.3倍くらい処理が速くなったりします。

DirectoryIndexを適切に記述する

index.*などワイルドカードを使うと遅くなります。また、先に書いたものから参照されるので、phpベースのサイトでインデックスページがほぼすべてindex.phpなら、「DirectoryIndex index.html index.php」と書かずに「DirectoryIndex index.php index.html」と書いた方が速いです。

もっと高度なテクニックについて

その他、Webサイトの負荷低減(パフォーマンス向上)については、「ハイパフォーマンスWebサイト ―高速サイトを実現する14のルール」と「続・ハイパフォーマンスWebサイト ―ウェブ高速化のベストプラクティス」がすごく参考になります。

ハイパフォーマンスWebサイト ―高速サイトを実現する14のルール

ハイパフォーマンスWebサイト ―高速サイトを実現する14のルール
  • HTTPリクエストを減らす
  • CDNを使う
  • Expiresヘッダを設定する
  • コンポーネントをgzipする
  • スタイルシートは先頭に置く
  • スクリプトは最後に置く
  • CSS expressionの使用を控える
  • JavaScriptとCSSは外部ファイル化する
  • DNSルックアップを減らす
  • JavaScriptを縮小化する
  • リダイレクトを避ける
  • スクリプトを重複させない
  • ETagの設定を変更する
  • Ajaxをキャッシュ可能にする

続・ハイパフォーマンスWebサイト ―ウェブ高速化のベストプラクティス

続・ハイパフォーマンスWebサイト ―ウェブ高速化のベストプラクティス
  • Ajaxアプリケーションとパフォーマンス
  • 応答性の高いウェブアプリケーション
  • 初期ロードの分割
  • 実行をブロックしないスクリプトのロード
  • 非同期スクリプトの組み合わせ
  • インラインスクリプトの適切な位置
  • 効率的なJavaScriptコード
  • Comet
  • gzip圧縮再考
  • 画像の最適化
  • 主ドメインの細分化
  • ドキュメントのフラッシュ
  • iframeの取り扱い
  • CSSセレクタの単純化

vim派もemacs派も、どっちでもいけるzshrc

vimrc晒したので、zshrcも公開。まだbashな人もzshはじめてみませんか?bashが許されるのは小学生までらしいですよ!zshは何かと便利。

vim派もemacs派もとか書いたけど、bindkeyのオプションを「-v」にするか「-e」にするかだけだったりします。あとは、「zsh最強シェル入門」を是非読んでみてください。国内のzsh本でこれ以上のは知ってる限りないです。マジでオススメ!

設定が一部Mac向けなので直して使ってください。

.zshrc


autoload -U compinit
compinit

export LANG=ja_JP.UTF-8
limit coredumpsize 102400
setopt nobeep

## Keybind vim|emacs
bindkey -v
#bindkey -e

## Completion
setopt auto_param_keys
setopt correct
setopt list_packed
setopt list_types
setopt numeric_glob_sort

setopt auto_cd
setopt auto_pushd
setopt auto_resume
setopt equals
setopt extended_glob
setopt long_list_jobs
setopt magic_equal_subst
setopt print_eight_bit
setopt prompt_subst
unsetopt promptcr

## History
HISTFILE=${HOME}/.zsh-history
HISTSIZE=100000
SAVEHIST=100000

setopt extended_history
setopt hist_ignore_dups
setopt hist_ignore_space
setopt hist_no_store
setopt hist_verify
setopt share_history

autoload history-search-end
zle -N history-beginning-search-backward-end history-search-end
zle -N history-beginning-search-forward-end history-search-end
bindkey "^p" history-beginning-search-backward-end
bindkey "^n" history-beginning-search-forward-end

zshaddhistory() {
local line=${1%%$'\n'}
local cmd=${line%% *}

[[ ${#line} -ge 5
&& ${cmd} != (l[salf])
&& ${cmd} != (man)
]]
}

## Alias
alias mv='nocorrect mv'
alias cp='nocorrect cp'
alias mkdir='nocorrect mkdir'
alias screen='screen -U -d -R'
alias du="du -h"
alias df="df -h"
alias j="jobs -l"
alias where="command -v"
# ls
alias la='ls -a'
alias ll='ls -l'
alias lf='ls -F'
# vim
alias v='vim'
alias vr='vim -R'
# global alias
alias -g G='| grep'
alias -g L='| less'
alias -g H='| head'
alias -g T='| tail'

## Prompt
autoload colors
colors

PROMPT="%{${fg[red]}%}[%n@%m] %{${reset_color}%}"
PROMPT2="%{${fg[red]}%}[%n@%m] %{${reset_color}%}"
RPROMPT="%{${fg[green]}%}%/ %{${reset_color}%}"
SPROMPT="%{${fg[red]}%}%r is correct? [n,y,a,e]:%{${reset_color}%} "

zstyle ':completion:*:default' menu select=1
zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}

#export LESS='--tabs=4 --no-limit --LONG-PROMPT --ignore-case'

autoload smart-insert-last-word
zle -N insert-last-word smart-insert-last-word
zstyle :insert-last-word match '*([^[:space:]][[:alpha:]/\\][^[:space:]])*'
bindkey "^]" insert-last-word

export PATH=/opt/local/bin:/opt/local/sbin:$PATH
export MANPATH=/opt/local/man:$MANPATH
export DISPLAY=:0.0


MacでPHP書くためのvimrc

MacでPHP(特に言語に合わせたわけではないのでPHPじゃなくてもOK)書くために作ったvimrcを公開します。仕事で自分がコーディングする機会はほとんどないので、あまり効率よくないかもしれませんが、最近vimはじめた人とかの参考になればいいなと。

プラギンは、AutoCompPop, snipMate, surround, taglist, NERD treeを利用。neocomplcacheも気になってて、そのうち使うかも。あと、以前、WindowsのGVIMも併用してたので、そちらでも動くようにしてあります。

注釈を英語で書いてるけど、英語力ないので文法は気にしない方向で…

注意事項

  • :と;を入れ替えてます

.vimrc


autocmd!

"" General
set nocompatible
filetype plugin indent on

set enc=utf-8
set tenc=utf-8
set ff=unix
set ffs=unix,dos,mac
set ambiwidth=double
set history=100
set magic

"" Define DOTVIM directory
if has('win32') || has('win64')
let $DOTVIM=$VIM."/vimfiles"
else
let $DOTVIM=$HOME."/.vim"
endif

"" Backup
set backup
set backupdir=$DOTVIM/backup
set directory=$DOTVIM/tmp
if !isdirectory(&backupdir)
call mkdir(&backupdir)
endif
if !isdirectory(&directory)
call mkdir(&directory)
endif

"" Colors
set background=dark
if has('syntax')
syntax enable
colorscheme desert
endif

"" Text format
set ts=4 sw=4 sts=0
set autoindent
set smartindent
set expandtab
set smarttab
set formatoptions=tcqor

"" Complement
set wildmode=list:full
set wildignore+=*.DS_Store

"" User interface
set number
set ruler
"set cursorline
set backspace=eol,indent,start
set cmdheight=1
set hidden
set list
set listchars=tab:>-,trail:_,extends:>,precedes:<
set mouse=a
set nowrap
set report=0
set scrolloff=5
set showcmd
set showmode
set title
set titlestring=Vim:\ %f\ %h%r%m
set visualbell
set whichwrap=b,s,<,>,[,]
set wildmenu

set laststatus=2
set statusline=%<%F\ %r%h%w%y%{'['.(&fenc!=''?&fenc:&enc).']['.&ff.']'}%=%4v(ASCII=%03.3b,HEX=%02.2B)\ %l/%L(%P)%m

"" Search
set ignorecase
set smartcase
set hlsearch
set noincsearch
set nowrapscan

"" vimrc edit/reload
nnoremap <silent> <Space>ev :<C-u>edit $MYVIMRC<CR>
nnoremap <silent> <Space>rv :<C-u>source $MYVIMRC<CR>

"" help
nnoremap <C-h> :<C-u>help<Space>
"" help current keyword
nnoremap <C-h><C-h> :<C-u>help<Space><C-r><C-w><CR>

"" Keybind
noremap ; :
noremap : ;

noremap j gj
noremap k gk
noremap gj j
noremap gk k

inoremap <C-h> <Left>
inoremap <C-j> <Down>
inoremap <C-k> <Up>
inoremap <C-l> <Right>
inoremap <C-a> <Home>
inoremap <C-e> <End>
inoremap <C-d> <Del>

"" Commet out
vnoremap co/ :s/^/\/\//<CR>:nohlsearch<CR>
vnoremap co# :s/^/#/<CR>:nohlsearch<CR>
vnoremap co" :s/^/\"/<CR>:nohlsearch<CR>
vnoremap cod :s/^\/\/\\|^[#"]//<CR>:nohlsearch<CR>
vnoremap co* v`<I<CR><esc>k0i/*<ESC>`>j0i*/<CR><esc><ESC>
vnoremap co< v`<I<CR><esc>k0i<!--<ESC>`>j0i--><CR><esc><ESC>

"" Complement Date and Time
inoremap <expr> ,df strftime('%Y-%m-%dT%H:%M:%S')
inoremap <expr> ,dd strftime('%Y-%m-%d')
inoremap <expr> ,dt strftime('%H:%M:%S')

"" Registers and Marks
nnoremap <Space>m :<C-u>marks
nnoremap <Space>r ;<C-u>registers

"" Select last edited text
nnoremap gc `[v`]
vnoremap gc :<C-u>normal gc<CR>
onoremap gc :<C-u>normal gc<CR>

"" Override syntax highlight
autocmd ColorScheme * highlight TabLine cterm=NONE ctermfg=lightgray ctermbg=darkgray
doautocmd ColorScheme _

" Highlight cursor line
autocmd WinEnter * setlocal cursorline
autocmd WinLeave * setlocal nocursorline

"" Reload with encoding command
command! -bang -bar -complete=file -nargs=? Utf8 edit<bang> ++enc=utf-8 <args>
command! -bang -bar -complete=file -nargs=? Eucjp edit<bang> ++enc=euc-jp <args>
command! -bang -bar -complete=file -nargs=? Cp932 edit<bang> ++enc=cp932 <args>
command! -bang -bar -complete=file -nargs=? Iso2022jp edit<bang> ++enc=iso-2022-jp <args>
command! -bang -bar -complete=file -nargs=? Sjis Cp932<bang> <args>
command! -bang -bar -complete=file -nargs=? Jis Iso2022jp<bang> <args>

"" Set file encording
command! Ceutf8 setlocal fenc=utf-8
command! Ceeucjp setlocal fenc=euc-jp
command! Cecp932 setlocal fenc=cp932
command! Ceiso2022jp setlocal fenc=iso-2022-jp
command! Cesjis Cecp932
command! Cejis Ceiso2002jp

"" Completion :cd
command! -complete=customlist,CompleteCD -nargs=? CD cd <args>
function! CompleteCD(arglead, cmdline, cursorpos)
let pattern = join(split(a:cmdline, '\s', !0)[1:], ' ') . '*/'
return split(globpath(&cdpath, pattern), "\n")
endfunction
cnoreabbrev <expr> cd
\ (getcmdtype() == ':' && getcmdline() ==# 'cd') ? 'CD' : 'cd'