Linux webサーバの構築方法

いちごパック > サーバ > Linux webサーバの構築方法

サーバPCにLinuxを最小インストール

Linuxとはカーネルの名前ですが、周辺ソフトを集めたディストリビューションの形でインストーラが配布されています。 まずはお好きなインストーラを使ってインストールします。 ここではDebianを入手し、 インストールする例を紹介します。
サーバPCの場合は、LinuxのCDイメージファイルをCD-RやDVD-Rに焼いて、それをサーバPCに入れて起動します。 VPSや仮想PCの場合は、LinuxのCDイメージファイルをCD-ROMドライブで指定して起動します。 インストール自体はほとんどボタンを押していくだけで、簡単です。
サーバとして運用するなら、インストール時は次の点に留意すると良いでしょう。
  • 予めIPアドレスを調べておき、ネットワークに接続する際はそのアドレスを与える。
  • HDD全体をLinuxとLinuxスワップ領域に割り当てる。
  • grubブートローダはマスターブートレコードにインストールする。
  • rootとは別に、自身が使うユーザアカウント(このページではichigoとします)を作っておく。
  • ソフト選択画面が表示されたら、必須システムツール以外のインストールチェックをすべて外す。必要なソフトは後で個別にインストールする。
  • ウィンドウシステムは入れない。


  • インストールが終わったら再起動して、Linuxサーバを起動します。
    起動後、サーバPCのコンソールにrootとしてログインし、rootで作業します。 この時点でsshサーバはインストールされていないはずです。

    簡易ファイアウォールの構築

    サーバのセットアップの前に、iptablesで簡易ファイアウォールを構築しておきます。 今回はIPv4のDNSのみを通し、それ以外の接続リクエストはすべて無視することにします。 最後の行は、TCPで自分から外部に接続した場合に、その接続中のパケットを受け入れることを指示しています。 セットアップ中の攻撃を阻止するためであれば、この設定で十分でしょう。
    % iptables -P INPUT DROP
    % ip6tables -P INPUT DROP
    % iptables -A INPUT -p udp --sport 53 -j ACCEPT
    % iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
    
    DHCPによってIPアドレスを取得している場合は、DHCPクライアント(UDPの68番)も通すようにします。
    % iptables -A INPUT -p udp --dport 68 -j ACCEPT
    
    なお、セットアップにIPv6を利用する場合は、もう少し複雑な設定が必要になります。

    不要なソフトの削除

    インストールされたソフトやサーバを確認します。 インストーラが何らかのサーバをインストールしているのであれば、 次のコマンドでTCPやUDPのポートがあいていることがわかります。 (lessがない場合はmoreを利用してください)
    % netstat -a -p -n | less
    
    意図しないプログラムが表示された場合は、 プログラム名を参考にしてサーバを停止させたうえで、アンインストールしてください。
    次に、インストールされたソフトを確認します。 Debianやubuntuでは次のコマンドを使います。
    % apt list --installed | less
    
    先のポート一覧とあわせて確認し、不要なソフトは消します。 例えばメールサーバeximがインストールされているなら、 次のコマンドでeximを削除します。
    % apt-get remove --purge exim4 exim4-base exim4-config exim4-daemon-light bsd-mailx
    

    必要なソフトの追加

    念のため、ソフト追加の前に、ファイアウォールが機能していることを確認します。
    % iptables -S
    % ip6tables -S
    
    INPUTのポリシーがDROPになっていれば機能しています。
    次に、サーバに何をインストールするか決めます。 パッケージの名前がわからない場合は、 aptitudeをインストールして起動するか、次のコマンドを実行します。
    % apt list | less
    
    ここでは、次のパッケージをインストールすることにします。
    パッケージ名内容
    dnsutilsDNSを呼び出すソフト(digやnslookup)
    iptables-persistentiptablesの設定を再起動時後も維持するソフト
    vimテキスト編集
    sudoroot権限でのプログラム実行
    openssh-serversshサーバ
    lighttpdwebサーバ

    パッケージのインストールにはapt(パッケージ管理システム)を使います。 aptはパッケージ入手先URLとして/etc/apt/sources.listに書かれた場所(複数可)を利用します。 /etc/apt/sources.listは、例えばjessieであれば次のようなファイルです。 入手先URLはOSのインストーラが自動設定してくれていますが、変更も可能です。
    deb http://ftp.jp.debian.org/debian/ jessie main
    deb http://ftp.jp.debian.org/debian/ jessie-updates main
    deb http://security.debian.org/ jessie/updates main
    
    最初に、aptに現在入手可能なパッケージのリストを取得させます。
    % apt-get update
    
    次に、必要なパッケージを入れます。 依存パッケージもインストールするか聞いてきますので、それらも一緒にインストールします。
    % apt-get install dnsutils iptables-persistent vim sudo openssh-server lighttpd
    
    インストールしたら、未設定のopensshサーバとwebサーバを停止させておきます。
    % /etc/init.d/ssh stop
    % /etc/init.d/lighttpd stop
    
    nanoではなくvimをエディタとして使いたい場合は、 次のコマンドでエディタとして/usr/bin/vim.basicを選択します。
    % update-alternatives --config editor
    

    opensshサーバの起動

    コンソール作業からリモート作業に変えるために、opensshサーバを設定し、 残りのセットアップはssh経由で行うことにします。 なお、コンソール作業が容易にできる環境でしたら、opensshサーバは使わないほうが良いでしょう。
    opensshサーバを起動する前に、 Port番号を22から別の番号(このページでは10022を例として説明します)に変更し、PermitRootLoginとPermitEmptyPasswordsをnoにしておきます。 その他の設定についても、可能な限り攻撃されにくい設定を選択すると良いでしょう。 PasswordAuthenticationについては最初はyesにしておき、パブリック鍵の登録が完了した時点でnoに変更すると良いでしょう。
    opensshサーバの詳しい設定方法や具体例については、 opensshdの設定方法が参考になるかとおもいます。
    opensshサーバの設定が完了したらopensshサーバを起動し、 opensshが使うTCPポートへのアクセスを通します。
    % /etc/init.d/ssh start
    % iptables -A INPUT -p tcp -m state --state NEW --dport 10022 -j ACCEPT
    
    ユーザichigoをsudoグループに追加し、sudoの権限を与えます。
    % gpasswd -a ichigo sudo
    
    クライアントPCからsshで接続してユーザichigoにパブリック鍵を登録し、 そのクライアントPCのプライベート鍵でログインできることが確認できれば、 PasswordAuthenticationをnoに変更したうえで、opensshサーバを再起動します。
    % /etc/init.d/ssh restart
    

    webサーバ(lighttpd)の起動

    ファイアウォールでINPUTチェインのHTTP(80番)を止めた状態で、 webサーバの設定を行い、webサーバを起動します。

    chrootの環境をつくる

    まずは最低限の環境をつくります。 この例では、/var/wwwにchroot用の環境をつくることにします。
    % mkdir /var/www
    % cd /var/www
    % mkdir html
    % mkdir log
    % chown www-data.www-data log
    

    ログファイルのリフレッシュを設定する

    chrootする場合は、ログファイルもchroot後に見える場所に置くことになります。 この例ではデフォルトの/var/logは見えませんので、 インストーラが設定したログファイルのリフレッシュも機能しなくなります。
    そこでlogrotateというソフトの設定を変更し、 /var/www/logに置かれたログファイルを定期的にリフレッシュさせます。 Debianではデフォルトでインストールされています。
    Debianでは、設定ファイルはlogrotate.dに収められています。 ここにログファイルのディレクトリを指定したファイルを置きます。
    % cd /etc/logrotate.d
    % cp lighttpd lighttpd.local
    
    オリジナルのlighttpd向けlogrotate.dの設定がありますので、 先頭行をchroot後のログファイル(この例では/var/www/log/*.log)に書き換えます。

    設定ファイルの作成

    まずは最低限の設定ファイルを作成します。 作成した設定ファイルは/etc/lighttpd/lighttpd.confとして保存します。 この例ではゼロから書いていますが、既存のコンフィグファイルを編集してもかまいません。
    server.chroot = "/var/www"
    server.modules = ("mod_access","mod_accesslog")
    server.document-root = "/html"
    
    accesslog.filename = "/log/access.log" server.errorlog = "/log/error.log" server.pid-file = "/lighttpd.pid" server.username = "www-data" server.groupname = "www-data" server.port = 80 index-file.names = ( "index.html" ) url.access-deny = ( "~", ".inc", ".old" )
    include_shell "/usr/share/lighttpd/create-mime.assign.pl"
    設定ファイルをテストし、起動します。
    % lighttpd -t -f /etc/lighttpd/lighttpd.conf
    
    設定ファイルのテストに成功しても、 www-dataがログファイルに書けない場合はエラー終了しますので、注意してください。

    chroot下でのperl環境の構築

    chrootで動かすために手間のかかる例として、CGI機能を使ってperlを動かす例を説明します。
    CGIを呼び出す場合は、/var/wwwの下に、 実行ファイルの実行に必要なファイルを集めた制限環境を整える必要があります。
    はじめに、必要なフォルダをつくります。
    % cd /var/www
    % mkdir dev
    % mknod -m 0666 /var/www/dev/null 1 3
    % mkdir bin
    % mkdir lib
    % mkdir etc
    % mkdir -m 1777 tmp
    
    次に、必要最低限のファイルを持ち込みます。 まずはperl本体をコピーします。
    % cd /var/www
    % cp /usr/bin/perl /var/www/bin/
    
    最低限の環境を作るためには、perlが使っている共有ライブラリをlddコマンドで調べて、コピーします。 linux-gate.so.1は実体がありませんので、無視してかまいません。
    % ldd /usr/bin/perl
            linux-gate.so.1 (0xb7787000)
            libdl.so.2 => /lib/i386-linux-gnu/i686/cmov/libdl.so.2 (0xb777b000)
            libm.so.6 => /lib/i386-linux-gnu/i686/cmov/libm.so.6 (0xb7735000)
            libpthread.so.0 => /lib/i386-linux-gnu/i686/cmov/libpthread.so.0 (0xb7718000)
            libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xb756b000)
            libcrypt.so.1 => /lib/i386-linux-gnu/i686/cmov/libcrypt.so.1 (0xb753a000)
            /lib/ld-linux.so.2 (0xb778a000)
    % cd /lib/i386-linux-gnu/i686/cmov/
    % cp libdl.so.2 libm.so.6 libpthread.so.0 libc.so.6 libcrypt.so.1 /var/www/lib/
    % cp /lib/ld-linux.so.2 /var/www/lib/
    
    コピーした共有ライブラリに依存ファイルがないか確認します。
    % cd /var/www/lib
    % ldd *
    ld-linux.so.2:
            statically linked
    libcrypt.so.1:
            linux-gate.so.1 (0xb7730000)
            libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xb754a000)
            /lib/ld-linux.so.2 (0xb7733000)
    libc.so.6:
            /lib/ld-linux.so.2 (0xb77aa000)
            linux-gate.so.1 (0xb77a7000)
    libdl.so.2:
            linux-gate.so.1 (0xb7703000)
            libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xb7549000)
            /lib/ld-linux.so.2 (0xb7706000)
    libm.so.6:
            linux-gate.so.1 (0xb76f4000)
            libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xb74f9000)
            /lib/ld-linux.so.2 (0xb76f7000)
    libpthread.so.0:
            linux-gate.so.1 (0xb778e000)
            libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xb75bd000)
            /lib/ld-linux.so.2 (0xb7791000)
    
    これ以上の依存ファイルはなく、perlコマンドが起動できることがわかります。
    作成した環境で、試しにperlを実行してみます。
    % chroot --userspec=www-data:www-data /var/www /bin/perl -e "print \"test\n\""
    perl: warning: Setting locale failed.
    perl: warning: Please check that your locale settings:
            LANGUAGE = "en_US:en",
            LC_ALL = (unset),
            LANG = "en_US.UTF-8"
        are supported and installed on your system.
    perl: warning: Falling back to the standard locale ("C").
    test
    
    ロケール情報はファイル /usr/lib/locale/locale-archive に入っています。 このファイルをコピーします。
    % mkdir -p usr/lib/locale
    % cp /usr/lib/locale/locale-archive /var/www/usr/lib/locale/
    
    今度はエラーが出ません。
    % chroot --userspec=www-data:www-data /var/www /bin/perl -e "print \"test\n\""
    test
    
    環境構築が完了したら、作成に利用したコマンド群をスクリプトとして保存しておくと良いでしょう。 ソフトが更新されたときには、保存したコマンドを再度実行します。
    #! /bin/sh
    cd /var/www
    cp /usr/bin/perl /var/www/bin/
    cd /lib/i386-linux-gnu/i686/cmov/
    cp libdl.so.2 libm.so.6 libpthread.so.0 libc.so.6 libcrypt.so.1 /var/www/lib/
    cd /var/www
    cp /lib/ld-linux.so.2 /var/www/lib/
    cp /usr/lib/locale/locale-archive /var/www/usr/lib/locale/
    

    chroot下でCGIを動かす

    chrootの下でperlが動作するようになったら、CGIの機能を追加します。 今回は /var/www/html/cgi/ の下にあり、 実行権限(chmod 755 ファイル名)を持つファイルをCGIとして実行できるように設定し、 /var/www/html/cgi/test.plに置かれた次のCGIファイルを実行する例を説明します。
    #! /bin/perl
    print "Content-type: text/plain\n\n";
    foreach $key (sort(keys(%ENV))) {
      $value=$ENV{$key};
      print "$key=$value\n";
    }
    
    CGIを実行可能にするには、設定ファイルlighttpd.confの最後に次の行を追加します。
    server.modules += ("mod_cgi")
    cgi.execute-x-only = "enable"
    static-file.exclude-extensions = (".pl", ".cgi")
    $HTTP["url"] =~ "^/cgi/" {
      cgi.assign = (".pl" => "/bin/perl", ".cgi" => "")
    }
    
    設定ファイルが正しいことを確認のうえ、lighttpdを再起動します。
    % lighttpd -t -f lighttpd.conf
    Syntax OK
    % /etc/init.d/lighttpd restart
    
    この状態でwebサーバが使うTCPポートを外部アクセス可能な状態にして、 http://<サーバのIPアドレス>/cgi/test.pl にアクセスすれば、 ブラウザ情報など、CGIに渡された環境変数を確認できます。
    webサーバが使うTCPポートへのアクセスは、次のファイルウォールの再構築で行います。

    ファイアウォールの再構築

    詳しい説明はiptablesを使ったIPv4/v6ファイアウォールの構築にありますが、 必要なソフトのインストールが終わった時点で、ファイアウォールを再構築します。
    例えば、IPv4のみを利用し、IPv6へのアクセスを拒否したいのでしたら次のようにします。 IPv6を有効にする場合の例はiptablesを使ったIPv4/v6ファイアウォールの構築をご覧ください。
    % iptables -F
    % iptables -X
    % iptables -Z
    % iptables -A INPUT -i lo -j ACCEPT
    % iptables -A OUTPUT -o lo -j ACCEPT
    % iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
    % iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
    % iptables -A INPUT -p tcp -m state --state NEW --dport 80 -j ACCEPT
    % iptables -A INPUT -p tcp -m state --state NEW --dport 10022 -j ACCEPT
    % iptables -A INPUT -p udp -s <DNSサーバ> --sport 53 -j ACCEPT
    % iptables -A OUTPUT -p udp -d <DNSサーバ> --dport 53 -j ACCEPT
    % iptables -A INPUT -p udp -s <NTPサーバ> --sport 123 -j ACCEPT
    % iptables -A OUTPUT -p udp -d <NTPサーバ> --dport 123 -j ACCEPT
    % iptables -A OUTPUT -p tcp --dport 80 \
        -d <Linuxアップデートサーバ> -j ACCEPT
    % iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix \
        "iptables denied [in]: " --log-level 7
    % iptables -A OUTPUT -m limit --limit 5/min -j LOG --log-prefix \
        "iptables denied [out]: " --log-level 7
    % iptables -A INPUT -j DROP
    % iptables -A OUTPUT -j DROP
    % iptables -A FORWARD -j DROP
    
    % ip6tables -A INPUT -j DROP % ip6tables -A OUTPUT -j DROP % ip6tables -A FORWARD -j DROP
    DNSサーバ、NTPサーバ、アップデートサーバには(数字の)IPアドレスを指定します。 複数のアドレスがある場合は、コマンドを複数回実行します。 また、10022の部分は、sshサーバのTCPポートを指定します。
    この例ではポリシー(-Pオプション)を利用せず最後に明示的にDROPしていますので、ポリシーは何でもかまいません。
    最後に、IPv4/v6のファイアウォール設定が起動時に読み込まれるように、設定を保存します。iptables-persistent
    % netfilter-persistent save