RailsをApache上で動かすためのモジュールPhusion Passenger
Rails(3.0.10)をPhusion Passenger上で動かしたときのメモ。サーバーはさくらインターネットのVPS、OSはCentOS。
Phusion Passengerは、RailsをApache(WEBサーバー)上で動かすためのApacheモジュール。Railsを動かすためのWEBサーバーは、開発環境ではWEBrick、本番環境ではMongrelが使われることが多かったが、これらは簡単に使える反面、動作速度やメモリ使用量ではイマイチだった。また、Apacheが入っているのに、Rails専用のWEBサーバーアプリケーションを別個にインストールしないといけないのもイマイチだった?というのが、Phusion Passengerが開発された背景なんだと思う。(WEBや書籍を斜め読みした。)
他のWEBサーバーと比べて動作速度やメモリ使用量の違いは一目瞭然。
Advantages of using Passenger + Apache over Webrick - stackoverflow
手順は以下の通り。
1. Passengerをインストールする
以下のコマンドを実行する。
$ gem list passenger # Passengerが入っていないことを確認 *** LOCAL GEMS *** # 何も表示されない。 $ sudo gem install passenger # Passengerのgemをインストール ... $ sudo passenger-install-apache2-module # Apacheのモジュールをインストールするコマンド ... Installation instructions for required software * To install Curl development headers with SSL support: Please run yum install curl-devel as root. * To install Apache 2 development headers: Please run yum install httpd-devel as root. * To install Apache Portable Runtime (APR) development headers: Please run yum install apr-devel as root. * To install Apache Portable Runtime Utility (APU) development headers: Please run yum install apr-util-devel as root. If the aforementioned instructions didn't solve your problem, then please take a look at the Users Guide: /usr/local/lib/ruby/gems/1.8/gems/passenger-3.0.9/doc/Users guide Apache.html
インストールにはもっとソフトウェアが必要と言われてインストールが中断されるので、足りないものをインストールして再実行。僕の場合は上記のライブラリ。
# 足りないライブラリをインストール $ sudo yum install httpd-devel $ sudo yum install apr-devel $ sudo yum install apr-util-devel # 再度passenger-install-apache2-moduleを実行 $ sudo passenger-install-apache2-module ... The Apache 2 module was successfully installed. # Apacheの設定ファイルへ追記する その1 Please edit your Apache configuration file, and add these lines: LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/gems/passenger-3.0.9/ext/apache2/mod_passenger.so PassengerRoot /usr/local/lib/ruby/gems/1.8/gems/passenger-3.0.9 PassengerRuby /usr/local/bin/ruby After you restart Apache, you are ready to deploy any number of Ruby on Rails applications on Apache, without any further Ruby on Rails-specific configuration! Press ENTER to continue. # Apacheの設定ファイルに追記する その2 -------------------------------------------- Deploying a Ruby on Rails application: an example Suppose you have a Rails application in /somewhere. Add a virtual host to your Apache configuration file and set its DocumentRoot to /somewhere/public: <VirtualHost *:80> ServerName www.yourhost.com DocumentRoot /somewhere/public # <-- be sure to point to 'public'! <Directory /somewhere/public> AllowOverride all # <-- relax Apache security settings Options -MultiViews # <-- MultiViews must be turned off </Directory> </VirtualHost>
2. Apacheの設定ファイル(httpd.conf)を編集する
インストールが終了すると、Apacheの設定ファイル(httpd.conf)に何を書けばよいか、わかりやすく提示してくれた(上記のログ)。さっそくその通りに編集してみる。
$ sudo vi /etc/httpd/conf/httpd.conf # httpd.confの編集 ... # Dynamic Shared Object (DSO) Support ... # Passenger LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/gems/passenger-3.0.9/ext/apache2/mod_passenger.so # 追記 PassengerRoot /usr/local/lib/ruby/gems/1.8/gems/passenger-3.0.9 # 追記 PassengerRuby /usr/local/bin/ruby # 追記 ... # VirtualHost example: # Almost any Apache directive may go into a VirtualHost container. # The first VirtualHost section is used for requests without a known # server name. <VirtualHost *:80> ServerName wwwXXXXXX.sakura.ne.jp DocumentRoot /var/www/demo/public # Railsアプリケーション直下のpublicフォルダを指定 <Directory /var/www/demo/public> AllowOverride all # ディレクトリごとの設定(.htaccessファイル)での上書きを許可する Options -MultiViews # MultiViewsを有効にする </Directory> </VirtualHost> $ sudo /etc/init.d/httpd restart # Apacheを再起動
VirtualHostのところの設定が何を意味しているかわからなかったので調べてみた。
そもそもVirtualHostとは、ひとつのサーバーで複数のドメイン名のWEBサイトを運用するための仕組み。たとえば、www.myapp1.comとwww.myapp2.comのドメインを同じサーバーで運用することができる。詳しくはバーチャルホストの例 Apacheを参照のこと。
Directoryの「AllowOverride all」は、httpd.confの設定をユーザーによる設定で上書きできるかということ。ユーザーによる設定は、ディレクトリごとに.htaccessファイルを作って設定内容を書き込むことでできる。.htaccessファイルの詳細は、バーチャルホストの例 Apacheを参照のこと。
同じくDirectoryの「Options -MultiViews」は、HTTPのリクエストヘッダによって適切なコンテンツを返す設定を有効にするという意味。たとえば、Accept-Languageヘッダ値に「en」が優先されていれば英語版のファイル、「ja」が優先されていれば日本語版のファイルを送り出すようなことができるようだ。ITmedia エンタープライズ : Linux Tips「ApacheのMultiViews機能ってなに?」
3. Railsのサンプルアプリを作成する
前回、最新(3.1.1)のRailsをインストールしたが、手元の書籍のRailsのバージョンは3.0.xだったので、まずはダウングレードする。
$ rails -v Rails 3.1.1 $ sudo gem install rails --version 3.0.10 --no-rdoc $ sudo gem uninstall rails --version 3.1.1 $ rails -v Rails 3.0.10
そして、アプリケーションを新規に作成する。
$ cd /var/www/html $ sudo rails new demo -d mysql # DBを指定してアプリケーションを新規作成 $ cd demo $ sudo bundle install # 足りないライブラリをインストール $ sudo rails generate scaffold Post name:string title:string content:text # Postという名前のモデル、ビュー、コントローラーの一式を作成 $ sudo rake db:create RAILS_ENV=production # DBを新規作成 $ sudo rake db:migrate RAILS_ENV=production # テーブルを新規作成
ブラウザでhttp://wwwXXXXXX.sakura.ne.jp:3000/postsを開いて、demoアプリケーションの画面が表示されたのでこれでOK。
と思いきや、上記のやり方だと、アプリケーションのディレクトリやファイルのオーナーはrootになっている。rootだとログファイルにログを書き込めないなどの問題が出る。そこで、logとtmpディレクトリのオーナーとパーミションを変更する。
$ ls -l /var/www/html/demo/log -rw-rw-rw- 1 root root 0 Nov 14 23:11 development.log -rw-rw-rw- 1 root root 0 Nov 14 23:39 production.log -rw-rw-rw- 1 root root 0 Nov 14 23:11 server.log -rw-rw-rw- 1 root root 0 Nov 14 23:11 test.log
この状態でURLにアクセスしても、production.logのファイルサイズは0のまま。以下のようにディレクトリのオーナーとパーミションを変更する。
$ cd /var/www/html/demo $ sudo chown -R montecut:users log tmp # オーナーをmontecutに変更 $ sudo chmod 755 -R log tmp # アクセス権を設定 $ sudo service httpd restart # Apacheを再起動
複数人でサーバーを使うことを考えると、本当はオーナーは個人のログインアカウントでない方がいいかも。とりあえず、これでURL(http://wwwXXXXXX.sakura.ne.jp:3000/posts)を開く。その後、ログファイルを確認すると、ファイルサイズが増えていることが確認できる。
$ ls -l /var/www/html/demo/log -rwxr-xr-x 1 montecut users 0 Nov 14 23:11 development.log -rwxr-xr-x 1 montecut users 251 Nov 14 23:39 production.log -rwxr-xr-x 1 montecut users 0 Nov 14 23:11 server.log -rwxr-xr-x 1 montecut users 0 Nov 14 23:11 test.log
さくらVPSにRuby Enterprise Editionをインストールして、Railsのサンプルアプリを作成する
さくらVPS(CentOS)にRuby Enterprise Editionをインストールしたときのメモ。REE以外にも、MySQL、Apache、Railsをインストールして、サンプルサプリを作成する。
REEの公式ページによると、REEはPhusion Passenger(Railsを実行するためのApacheモジュール)を使ったときに、メモリ使用量が33%削減するらしい。通常のRuby1.8.7との互換も100%とのこと。
Ruby Enterprise Editionのインストールには、さくらVPSのCentOSにRuby Enterprise Editionをインストール id: kadoppeさんの記事を参考にさせていただいた。
1. Ruby Enterprise Editionのインストール
$ wget http://rubyenterpriseedition.googlecode.com/files/ruby-enterprise-1.8.7-2011.03.tar.gz # ファイルをダウンロード $ tar zxvf ruby-enterprise-1.8.7-2011.03.tar.gz # ファイルを展開 $ cd ruby-enterprise-1.8.7-2011.03 $ sudo ./installer # インストーラーを実行 Welcome to the Ruby Enterprise Edition installer This installer will help you install Ruby Enterprise Edition 1.8.7-2011.03. Don't worry, none of your system files will be touched if you don't want them to, so there is no risk that things will screw up. You can expect this from the installation process: 1. Ruby Enterprise Edition will be compiled and optimized for speed for this system. 2. Ruby on Rails will be installed for Ruby Enterprise Edition. 3. You will learn how to tell Phusion Passenger to use Ruby Enterprise Edition instead of regular Ruby. Press Enter to continue, or Ctrl-C to abort. Checking for required software... * C compiler... found at /usr/bin/gcc * C++ compiler... found at /usr/bin/g++ * The 'make' tool... found at /usr/bin/make * The 'patch' tool... found at /usr/bin/patch * Zlib development headers... not found * OpenSSL development headers... not found * GNU Readline development headers... not found Some required software is not installed. But don't worry, this installer will tell you how to install them. Press Enter to continue, or Ctrl-C to abort.
「必要なライブラリが入ってないよ!」と言われるので、インストールする。
$ sudo -i # yum -y install readline-devel # yum -y install zlib-devel # yum -y install openssl-devel
再度インストーラーを実行。途中で、どのディレクトリにインストールするか聞いてくるので、/usr/localと入力する。
# ./installer # インストーラーを実行 ... Where would you like to install Ruby Enterprise Edition to? (All Ruby Enterprise Edition files will be put inside that directory.) [/opt/ruby-enterprise-1.8.7-2011.03] : /usr/local # ここに入力する ... ... # mysqlのgemがインストールできなかったというエラー -------------------------------------------- Warning: some libraries could not be installed The following gems could not be installed, probably because of an Internet connection error: * mysql These gems are not required, i.e. Ruby Enterprise Edition will work fine without them. But most people use Ruby Enterprise Edition in combination with Phusion Passenger and Ruby on Rails, which do require one or more of the aforementioned gems, so you may want to install them later. To install the aforementioned gems, please use the following commands: * /usr/local/bin/ruby /usr/local/bin/gem install mysql Press ENTER to show the next screen. ... # Phusion Passengerについての注意事項 -------------------------------------------- Ruby Enterprise Edition is successfully installed! If want to use Phusion Passenger (http://www.modrails.com) in combination with Ruby Enterprise Edition, then you must reinstall Phusion Passenger against Ruby Enterprise Edition, as follows: /usr/local/bin/passenger-install-apache2-module Make sure you don't forget to paste the Apache configuration directives that the installer gives you. # アンインストール方法 If you ever want to uninstall Ruby Enterprise Edition, simply remove this directory: /usr/local If you have any questions, feel free to visit our website: http://www.rubyenterpriseedition.com Enjoy Ruby Enterprise Edition, a product of Phusion (www.phusion.nl) :-)
mysqlのgemがインストールできなかったと出る。
2. MySQLのインストール
mysqlのgemがインストールできなかったのは、MySQLそのものがインストールされていないことが原因かもしれない。まずMySQLをインストールしてからにしてみる。
# yum install mysql-server # MySQLをインストール # /usr/local/bin/ruby /usr/local/bin/gem install mysql # mysqlのgemをインストール Building native extensions. This could take a while... ERROR: Error installing mysql: ERROR: Failed to build gem native extension. /usr/local/bin/ruby extconf.rb checking for mysql_ssl_set()... no checking for rb_str_set_len()... no checking for rb_thread_start_timer()... no checking for mysql.h... no checking for mysql/mysql.h... no *** extconf.rb failed *** Could not create Makefile due to some reason, probably lack of necessary libraries and/or headers. Check the mkmf.log file for more details. You may need configuration options. Provided configuration options: --with-opt-dir --without-opt-dir --with-opt-include --without-opt-include=${opt-dir}/include --with-opt-lib --without-opt-lib=${opt-dir}/lib --with-make-prog --without-make-prog --srcdir=. --curdir --ruby=/usr/local/bin/ruby --with-mysql-config --without-mysql-config Gem files will remain installed in /usr/local/lib/ruby/gems/1.8/gems/mysql-2.8.1 for inspection. Results logged to /usr/local/lib/ruby/gems/1.8/gems/mysql-2.8.1/ext/mysql_api/gem_make.out
mysqlのgemのインストールでエラーが出た。原因はよくわからないが、 mysql-serverだけでは足りないっぽい。以下のように、mysqlとmysql-develもインストールするとエラーが出なくなった。
# yum -y mysql mysql-devel ... Complete! # /usr/local/bin/ruby /usr/local/bin/gem install mysql Building native extensions. This could take a while... Successfully installed mysql-2.8.1 # 今度は成功 1 gem installed Installing ri documentation for mysql-2.8.1... Installing RDoc documentation for mysql-2.8.1...
今度はmysqlのgemを無事インストールできた。ついでに、MySQLを起動しておく。
# /etc/rc.d/init.d/mysqld start # サービスを起動 # /sbin/chkconfig mysqld on # MySQLの自動起動をONにする
3. Apacheのインストール
Apacheをまだインストールしていなかったらインストールする。さくらVPS設定その2 Apache+MySQL+WordPress id:r7kamuraさんの記事が参考になる。
4. Railsのインストール
最新版のRailsをインストールする。
$ sudo gem install rails --no-rdoc # ドキュメント不要 -bash: gem: command not found
おっと、gemにパスが通っていないため見つからない。これまでのように毎回フルパスを入力するのは面倒なので、以下のようにbashの設定ファイルにパスを書き込む。さくらVPS設定その1 User+SSH+Firewall id:r7kamuraさんの記事が参考になる。
$ vi ~/.bash_profile # ファイルを編集する PATH=$PATH:$HOME/bin # この行の後に... PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin # この行を追加 # 「:wq」で保存後、以下のコマンドで設定を再読み込みする。 $ source ~/.bash_profile
あらためてrailsをインストール。
$ sudo gem install rails --no-rdoc # ドキュメント不要
iptables(ファイヤーウォール)でRailsのポートを開けていない場合は、以下のコマンドで設定しておく。
$ sudo vi /etc/sysconfig/iptables -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 3000 -j ACCEPT # 追加 $ sudo /etc/rc.d/init.d/iptables restart # 再起動 $ sudo sudo iptables -L # 設定の確認
5. サンプルアプリケーションの作成
サンプルアプリケーションを作って実行してみる。
$ mkdir ~/workspace # ホームディレクトリにworkspaceフォルダを作る $ cd ~/workspace $ rails new demo -d mysql # DBを指定してアプリケーションを新規作成 ... run bundle install Enter your password to install the bundled RubyGems to your system:
「足りないgemをインストールするからパスワード入れてよ」と言われるので、ログインユーザーのパスワードを入力する。すると、以下のようにたくさんインストールしてくれた。
.. Installing coffee-script-source (1.1.3) Installing execjs (1.2.9) Installing coffee-script (2.2.0) ... Installing coffee-rails (3.1.1) Installing jquery-rails (1.0.17) Installing mysql2 (0.3.10) with native extensions ... Installing sass (3.1.10) Installing sass-rails (3.1.4) Installing uglifier (1.0.4) Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
とりあえず、デモアプリに必要な準備をする。
$ rails generate scaffold Post name:string title:string content:text # Postという名前のモデル、ビュー、コントローラーを作成 $ rake db:create # DBを作成 $ rake db:migrate # テーブルを作成 $ rake routes # URLのルーティングを確認(/postsにアクセスすればよいことがわかる) posts GET /posts(.:format) {:action=>"index", :controller=>"posts"} POST /posts(.:format) {:action=>"create", :controller=>"posts"} new_post GET /posts/new(.:format) {:action=>"new", :controller=>"posts"} edit_post GET /posts/:id/edit(.:format) {:action=>"edit", :controller=>"posts"} post GET /posts/:id(.:format) {:action=>"show", :controller=>"posts"} PUT /posts/:id(.:format) {:action=>"update", :controller=>"posts"} DELETE /posts/:id(.:format) {:action=>"destroy", :controller=>"posts"}
作成したアプリケーションのルートディレクトリでサーバーを起動する。
$ rails server /usr/local/lib/ruby/gems/1.8/gems/execjs-1.2.9/lib/execjs/runtimes.rb:47:in `autodetect': Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable) from /usr/local/lib/ruby/gems/1.8/gems/execjs-1.2.9/lib/execjs.rb:5 from /usr/local/lib/ruby/gems/1.8/gems/coffee-script-2.2.0/lib/coffee_script.rb:1:in `require' from /usr/local/lib/ruby/gems/1.8/gems/coffee-script-2.2.0/lib/coffee_script.rb:1 from /usr/local/lib/ruby/gems/1.8/gems/coffee-script-2.2.0/lib/coffee-script.rb:1:in `require' from /usr/local/lib/ruby/gems/1.8/gems/coffee-script-2.2.0/lib/coffee-script.rb:1 from /usr/local/lib/ruby/gems/1.8/gems/coffee-rails-3.1.1/lib/coffee-rails.rb:1:in `require' from /usr/local/lib/ruby/gems/1.8/gems/coffee-rails-3.1.1/lib/coffee-rails.rb:1 from /usr/local/lib/ruby/gems/1.8/gems/bundler-1.0.21/lib/bundler/runtime.rb:68:in `require' from /usr/local/lib/ruby/gems/1.8/gems/bundler-1.0.21/lib/bundler/runtime.rb:68:in `require' from /usr/local/lib/ruby/gems/1.8/gems/bundler-1.0.21/lib/bundler/runtime.rb:66:in `each' from /usr/local/lib/ruby/gems/1.8/gems/bundler-1.0.21/lib/bundler/runtime.rb:66:in `require' from /usr/local/lib/ruby/gems/1.8/gems/bundler-1.0.21/lib/bundler/runtime.rb:55:in `each' from /usr/local/lib/ruby/gems/1.8/gems/bundler-1.0.21/lib/bundler/runtime.rb:55:in `require' from /usr/local/lib/ruby/gems/1.8/gems/bundler-1.0.21/lib/bundler.rb:122:in `require' from /home/montecut/workspace/demo/config/application.rb:7 from /usr/local/lib/ruby/gems/1.8/gems/railties-3.1.1/lib/rails/commands.rb:52:in `require' from /usr/local/lib/ruby/gems/1.8/gems/railties-3.1.1/lib/rails/commands.rb:52 from /usr/local/lib/ruby/gems/1.8/gems/railties-3.1.1/lib/rails/commands.rb:49:in `tap' from /usr/local/lib/ruby/gems/1.8/gems/railties-3.1.1/lib/rails/commands.rb:49 from script/rails:6:in `require' from script/rails:6
エラーが出た。Rails 3.1 execjs and Could not find a JavaScript runtimeのページによると、JavaScriptライブラリをインストールすると解決するとのこと。Gemfileにgemを追記して、bundle installコマンドで足りないgemをインストールする。
$ vi Gemfile # アプリケーションのルート直下にあるGemfileを編集 gem 'execjs' # 追加 gem 'therubyracer' # 追加 $ bundle install # 足りないgemを入れてくれる $ rails server # 再度サーバーを起動
サーバーが起動したようなので、ブラウザから確認。http://wwwXXXXXX.sakura.ne.jp:3000/postsを開いて、demoアプリケーションの画面が表示されたのでこれでOK。
SSHのポート番号を変える
SSHの認証方式を、パスワード認証を禁止して公開鍵認証にすれば、SSHのポートからクラックされるリスクはかなり減る。しかし、外部からポートスキャンをされるたびにCPU負荷がかかるとのことなので、攻撃の対象になりやすいSSHはポート番号を変更しておくのが定番のようだ。
今日は以下のことを試してみる。サーバーはさくらインターネットのVPS(CentOS)。
1. デフォルトのSSHポート(22番)へのアクセス状況を調べる
Linuxのセキュリティ関連のログは、/var/log/secureに記録される。lessコマンドでファイルを開いてみる。ちなみに、lessコマンドを終了するには「q」をタイプする。「/キーワード」をタイプすればファイル内の文字列検索もできる。
$ sudo -i # rootになる # less /var/log/secure ... Nov 6 00:54:12 サーバー名 sshd[1752]: Invalid user hashimoto from 220.227.121.180 Nov 6 00:54:12 サーバー名 sshd[1752]: Address 220.227.121.180 maps to report.ksrtc.in, but this does not map back to the address - POSSIBLE BREAK-IN ATTEMPT! Nov 6 00:54:12 サーバー名 sshd[1753]: input_userauth_request: invalid user hashimoto Nov 6 00:54:12 サーバー名 sshd[1752]: pam_unix(sshd:auth): check pass; user unknown Nov 6 00:54:12 サーバー名 sshd[1752]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=220.227.121.180 Nov 6 00:54:12 サーバー名 sshd[1752]: pam_succeed_if(sshd:auth): error retrieving information about user hashimoto Nov 6 00:54:13 サーバー名 sshd[1752]: Failed password for invalid user hashimoto from 220.227.121.180 port 38485 ssh2 Nov 6 00:54:13 サーバー名 sshd[1753]: Received disconnect from 220.227.121.180: 11: Bye Bye ... Nov 6 00:55:05 サーバー名 sshd[1782]: Invalid user chikafuji from 220.227.121.180 Nov 6 00:55:05 サーバー名 sshd[1782]: Address 220.227.121.180 maps to report.ksrtc.in, but this does not map back to the address - POSSIBLE BREAK-IN ATTEMPT! Nov 6 00:55:05 サーバー名 sshd[1783]: input_userauth_request: invalid user chikafuji Nov 6 00:55:05 サーバー名 sshd[1782]: pam_unix(sshd:auth): check pass; user unknown Nov 6 00:55:05 サーバー名 sshd[1782]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=220.227.121.180 Nov 6 00:55:05 サーバー名 sshd[1782]: pam_succeed_if(sshd:auth): error retrieving information about user chikafuji Nov 6 00:55:07 サーバー名 sshd[1782]: Failed password for invalid user chikafuji from 220.227.121.180 port 49114 ssh2 Nov 6 00:55:08 サーバー名 sshd[1783]: Received disconnect from 220.227.121.180: 11: Bye Bye ...
適当なユーザー名とパスワードで手当たり次第に接続を試みられているっぽい。同様の接続がサーバーを立ててから6日間で12536件も。怖すぎ…。
ログの意味を調べてみた。
# 攻撃者のIPアドレスとドメイン名の正引き、逆引き結果が違う
Address 220.227.121.180 maps to report.ksrtc.in, but this does not map back to the address - POSSIBLE BREAK-IN ATTEMPT!
DNSでIPアドレス(220.227.121.180)からドメイン名(report.ksrtc.in)を逆引きした結果と、ドメイン名からIPアドレスを正引きした結果が違うということ。これでどうして「POSSIBLE BREAK-IN ATTEMPT!(攻撃の可能性あり!)」と言えるのか? ちょっとだけ調べてみると、メールサーバーでは逆引きした結果と正引きした結果が違うとスパムメールと判定することは割と多いみたい。逆引きと正引きの結果を変えることは攻撃者にとってどんなメリットがあるのかを調べてみたが、すぐには見つけられなかった。攻撃者が本当のドメイン名を知られないようにするためかなぁ…。
# PAMで認証エラー Nov 6 00:54:12 サーバー名 sshd[1752]: pam_unix(sshd:auth): check pass; user unknown Nov 6 00:54:12 サーバー名 sshd[1752]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=220.227.121.180 Nov 6 00:54:12 サーバー名 sshd[1752]: pam_succeed_if(sshd:auth): error retrieving information about user hashimoto
PAMはとは、Pluggable Authentication Moduleの略で、UNIXで共通化されている認証モジュールのようだ。このPAMから認証エラーのメッセージが出ている。
# パスワードでSSH2接続に失敗 Nov 6 00:54:13 サーバー名 sshd[1752]: Failed password for invalid user hashimoto from 220.227.121.180 port 38485 ssh2
これが重要。ログの最後にssh2とあるので、攻撃者はSSH2をパスワード認証で接続を試みていることがわかる。
2. SSHのポート番号を変更する
JFEテクノリサーチ株式会社さんのサイトがわかりやすいので参考になる。
以下の手順になる。
- 現在使われていないポートを調べて、新しいポート番号を決める
- SSHの設定ファイルにポート番号を追加する
- サービスの設定ファイルのポート番号を変更する
- iptables(ファイヤーウォール)の設定ファイルを変更する
- 動作確認
(1) 現在使われていないポートを調べて、新しいポート番号を決める
変更するポートは、現在使われていなくて、かつ今後も使われる可能性が少ないものにする必要がある。
現在使われていないポートを調べるには、以下のコマンドを実行する。
[user@server ~]$ netstat -antu Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN # 25番ポート(SMTP) tcp 0 0 :::80 :::* LISTEN # 80番ポート(HTTP) tcp 0 0 :::22 :::* LISTEN # 22番ポート(SSH) tcp 0 380 ::ffff:49.212.106.174:22 ::ffff:180.11.197.81:52561 ESTABLISHED # 22番ポートが接続中 udp 0 0 49.212.106.174:123 0.0.0.0:* udp 0 0 127.0.0.1:123 0.0.0.0:* udp 0 0 0.0.0.0:123 0.0.0.0:* udp 0 0 fe80::5054:ff:fe04:136:123 :::* udp 0 0 ::1:123 :::* udp 0 0 :::123 :::*
まだapacheしか入れていないので、ほとんどのポートが使われていませんね。オプションは、-aはdisplay all sockets (default: connected)、-nはdon't resolve names、-tはTCPを表示、-uはUDPを表示するという意味。
規定のポートも使わないようにする。0から1023 までの範囲は Well Known Portsとして決められているので使わない。1024から49151まではRegistered Portsと呼ばれ、様々なサービスが定義されているので使わない方が望ましい。9152から65535についてはDynamic or/and Private Portsと呼ばれていて、アプリケーションで勝手に使うためのものみたい。
(2) SSHの設定ファイルにポート番号を追加する
以下のコマンドを実行する。
$ sudo vi /etc/ssh/sshd_config #Port 22 # コメントアウト Port 任意の番号 # ポート番号を追加する $ sudo /etc/init.d/sshd restart
(3) サービスの設定ファイルのポート番号を変更する
以下のコマンドを実行する。(僕の環境では、このファイルを編集しなくても新しいポート番号で接続できた。)
$ sudo vi /etc/services #ssh 22/tcp SSH Remote Login Protocol # コメントアウトする #ssh 22/udp SSH Remote Login Protocol # コメントアウトする ssh ポート番号/tcp SSH Remote Login Protocol # 追加 ssh ポート番号/udp SSH Remote Login Protocol # 追加
(4) iptables(ファイヤーウォール)の設定ファイルを変更する
以下のコマンドを実行する。
$ sudo vi /etc/sysconfig/iptables # -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT # コメントアウト、または次の行のように書き換え -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport ポート番号 -j ACCEPT # 新規追加 $ sudo /etc/rc.d/init.d/iptables restart
(5) 動作確認
新しいポートでSSH2接続でログインできることを確認する。また、古いポート(22番)でログインできないことを確認する。注意事項としては、既存の接続を残したまま新規接続を試すこと。設定が間違っている状態で接続を切ってしまうと、もう接続できなくなってしまって困るから。
さくらVPSでセキュリティ関連の設定をする(ファイヤーウォール編)
SSHの設定に引き続き、ファイヤーウォール(iptables)の設定をする。
1. iptablesの設定
以下のサイトの説明がわかりやすいので、その通りにした。設定ファイルの場所は、/etc/sysconfig/iptables。
さくらのVPS を使いはじめる 3‐iptables を設定する
流れとしては、以下のようになる。
SSH, HTTP, FTP1, FTP2, MySQLのパケットを許可(ACCEPT)した。その後、iptablesがOS起動時に自動起動する設定になっているかを確認するために、以下のコマンドを実行する。
$ chkconfig --list iptables iptables 0:off 1:off 2:on 3:on 4:on 5:on 6:off # ランレベル2〜5のonを確認
もし上記のようになっていなければ、以下のコマンドで設定する。
$ sudo chkconfig iptables on # OS起動時に自動で起動するように設定
2. iptablesが効いているか確認
(1) ポートをスキャンするためのツールnmapをインストールする
さくらVPSのOSはCentOSなので、yumコマンドでインストールする。
$ yum list installed | grep nmamp # インストール済みでないことを確認(このコマンドで何も表示されない) # sudo -i # yum -y install nmap # yum の -y オプションは「すべてYESで答える」
(2) ポートをスキャンしてみる
以下のコマンドを実行すると、SSHとSMTPのポートだけが開いていることがわかる。「え? さっきiptablesの設定でACCEPTした他のポートはどうして開いていないの?」と思ったら、以前の記事をご覧いただきたい。ポートは、そのポートを使うアプリケーションが起動されていないと開かない。
# nmap localhost # ポートスキャンを実行 Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2011-11-07 00:22 JST Interesting ports on localhost.localdomain (127.0.0.1): Not shown: 1678 closed ports PORT STATE SERVICE 22/tcp open ssh 25/tcp open smtp Nmap finished: 1 IP address (1 host up) scanned in 0.061 seconds
ただ、この方法でポートをスキャンするだけだったら、iptablesの設定が効いているかどうかは判別できない。
(3) ブラウザでアクセスしてみる
「nmap localhost」のコマンドでは、iptablesが機能しているかどうかがわからないので、ブラウザを使ってパケットが届くかどうか試してみる。
まず、Apache*1を起動した状態で、ブラウザでVPSのURL(http://wwwXXXXXX.sakura.ne.jp)にアクセスする。
Apacheのページが表示される。
nmapコマンドを実行すると、80番ポート(HTTP)が開いていることがわかる。
# nmap localhost # ポートスキャンを実行 Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2011-11-10 01:34 JST Interesting ports on localhost.localdomain (127.0.0.1): Not shown: 1677 closed ports PORT STATE SERVICE 22/tcp open ssh 25/tcp open smtp 80/tcp open http Nmap finished: 1 IP address (1 host up) scanned in 0.140 seconds
次に、iptablesの設定ファイルを編集して、80番ポートへのパケットを拒否するようにしてみる。
$ sudo vi /etc/sysconfig/iptables # 設定ファイルを編集する ... -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT # -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT # ポート80をACCEPTしない -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT -A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited # ACCEPTしていないパケットをすべて拒否 $ sudo /etc/rc.d/init.d/iptables restart # iptablesを再起動する
この状態では、ブラウザでVPSのURLにアクセスしても、Apacheのページが表示されない。iptablesにより、ポート80番のパケットが破棄されているからである。
ポートは開いているが、このポートに入ってくるパケットはちゃんとブロックされている。
# nmap localhost # ポートスキャンを実行 Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2011-11-10 01:34 JST Interesting ports on localhost.localdomain (127.0.0.1): Not shown: 1677 closed ports PORT STATE SERVICE 22/tcp open ssh 25/tcp open smtp 80/tcp open http Nmap finished: 1 IP address (1 host up) scanned in 0.140 seconds
*1:Apacheのインストール方法は、「さくらVPS設定その2 Apache+MySQL+WordPress」のページを参考にさせていただいた。
さくらVPSでセキュリティ関連の設定をする(SSH編)
さくらインターネットのVPSでSSHの設定をしたときのメモ。サーバーのOSはCentOS、クライアントはWindows。
VPSの契約が完了すると「[さくらのVPS] 仮登録完了のお知らせ」というメールが届く。そこに書かれているIPアドレス、初期パスワードを使う。
SSH関連で設定すること
1. WEBのVPSコントロールパネルからrootのパスワードの変更と、ログインユーザーを作成する
(1) 「VPSコントロールパネル」にログインしVPSを起動する
仮登録完了のメールに書いてある通り、初期状態ではVPSは停止状態になっているので、WEBページのUIからVPSを起動する。以下のURLにアクセスして、メールに書いてあるIPアドレスとパスワードを入力。
https://secure.sakura.ad.jp/vpscontrol/
「仮想サーバ操作」で、[起動]ボタンを押す。ステータスが「起動中」になったことを確認。
(2) rootのパスワードを変更する
SSHクライアントにIPアドレス(メールに書いてある)、アカウント(root)、パスワード(メールに書いてある)を入力してSSH2でログインする。そして、passwdコマンドでrootのパスワードを変更する。
[root@server ~]# passwd Changing password for user root. New UNIX password: Retype new UNIX password: passwd: all authentication tokens updated successfully.
(3) 通常使うユーザーを作成する
adduserコマンドでユーザーを作成する。
# -D オプションで、デフォルトでどんなユーザーが作られるか確認 [root@server ~]# adduser -D GROUP=100 # 100はusersグループを意味する。「cat /etc/group」コマンドで確認できる。 HOME=/home INACTIVE=-1 EXPIRE= SHELL=/bin/bash SKEL=/etc/skel CREATE_MAIL_SPOOL=yes
# スーパーユーザー(root)特権を得ることのできるグループを設定 [root@server ~]# visudo ... # この行のコメントアウトを外して保存 %wheel ALL=(ALL) ALL ...
# ユーザーの追加とグループ、パスワードの設定 [root@server ~]# adduser ユーザー名 [root@server ~]# usermod -G wheel ユーザー名 # wheelグループへ追加 [root@server ~]# id ユーザー名 # グループの確認 uid=500(ユーザー名) gid=500(ユーザー名) groups=500(ユーザー名),10(wheel) [root@server ~]# passwd ユーザー名 Changing password for user ユーザー名. New UNIX password: Retype new UNIX password: passwd: all authentication tokens updated successfully.
これで、いったんexitコマンドでサーバーとの接続を切って、新しく作成したユーザーでログインできれば成功。
2. RSA公開鍵のファイルを作成してサーバーに配置する
パスワード認証だと外部からの攻撃でクラックされる可能性があるため、安全性の高いRSA公開鍵認証を使えるようにする。
(1) クライアント(ローカル環境)でRSA鍵を作成する
SSHクライアント(自分の場合はPoderosa)のメニューから、SSH鍵を作成する。アルゴリズムはRSA、ビット数は2048、適当なパスワードを指定して実行。「秘密鍵を名前をつけて保存」でsitename.ppk、「OpenSSH形式で公開鍵を名前をつけて保存」でsitename-openssh.pubというファイル名で保存。
(2) サーバーに公開鍵のファイルを配置する
サーバーで以下のコマンドを実行する。
$ mkdir ~/.ssh # 鍵を配置する.sshディレクトリを作成 $ chmod 700 ~/.ssh # 読み書き実行権限を付ける $ cd ~/.ssh $ touch authorized_keys # 公開鍵のファイルを作成 $ chmod 600 ~/.ssh/authorized_keys# 読み書き権限を付ける
そして、authorized_keysファイルを開き、(1)で作成したsitename-openssh.pubの内容をコピペして保存する
$ vi authorized_keys #
ssh-rsa XXXXXXXX... # (1)で作成したsitename-openssh.pubの内容をコピペして保存する
3. RSA公開鍵認証を有効にする設定、rootでのログインを禁止する設定をする
(1) sshd_configを編集する
$ su - # rootになる # vi /etc/ssh/sshd_config # sshの設定を編集 PermitRootLogin no # rootでのログインを禁止 RSAAuthentication yes # RSA認証を許可 PubkeyAuthentication yes # 公開鍵認証を許可 AuthorizedKeysFile .ssh/authorized_keys # 認証鍵ファイルを指定 PermitEmptyPasswords no # パスワードなしのログインを禁止 PasswordAuthentication no # パスワード認証を禁止 # /etc/rc.d/init.d/sshd restart # SSHサービスを再起動して設定を反映
Linuxでファイヤーウォール(iptables)が必要な理由
ネットワーク初心者の僕が、iptablesやポートの開放について勘違いしていたことをまとめる。
ネットワークやLinux関連の本やサイトでは必ず、「サーバーを立てるときはiptables(ファイヤーウォール)を設定しましょう」書いている。そして、iptablesの設定で必要ないポートは全部閉じることが推奨されている。
ここで、まずひとつ目の勘違い。
Q: iptablesを設定しなければ、すべてのポートが開放されている状態になり、どのポートも攻撃の対象になってしまう?
A: いいえ。iptablesが起動していなくても、すべてのポートが開放されている状態にはならない。ポートは、アプリケーションから利用されて初めて開かれた状態になる。なので、極端な話、外部と通信するアプリケーションをひとつも起動していない状態では、ポートはすべて閉じていることになり、外部からの攻撃で問題が出ることはない。
ポートが開いているかどうかは、nmapというツール*1で確かめることができる。以下の例のサーバーは、さくらインターネットのVPS。OSはCentOS。初期状態なので、WEBサーバー(Apache)すらも起動していない。このとき、開かれているポートはSSHとSMTPの2つのみ。
[user@server ~]$ sudo /etc/rc.d/init.d/iptables stop # iptabelsのサービスを停止(後でstartで戻しておくこと。) ... [user@server ~]$ nmap localhost # 自分自身(localhost)のポートの状態を調べる Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2011-11-08 20:42 JST Interesting ports on localhost.localdomain (127.0.0.1): Not shown: 1678 closed ports PORT STATE SERVICE 22/tcp open ssh 25/tcp open smtp Nmap finished: 1 IP address (1 host up) scanned in 0.138 seconds
ここでApache*2を起動すると、80のポートも開かれている状態になる。
[user@server ~]$ sudo apachectl start [user@server ~]$ nmap localhost Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2011-11-08 21:31 JST Interesting ports on localhost.localdomain (127.0.0.1): Not shown: 1677 closed ports PORT STATE SERVICE 22/tcp open ssh 25/tcp open smtp 80/tcp open http Nmap finished: 1 IP address (1 host up) scanned in 0.149 seconds
次に、ふたつ目の勘違い。
Q: アプリケーションを起動するまでポートが開かれないのなら、必要なアプリケーションだけ起動するように気をつければよく、わざわざiptablesでブロックする必要はないのでは?
A: いいえ。セキュリティは二重、三重にかけておいた方がよい。iptablesを使うメリットは以下の通り。
- 管理者が知らないうちにポートが使われることを防ぐ
- 細かくパケットをフィルタリングする
- ネットワークアドレスを変換する
1.は、アプリケーションはiptablesで許可されていないポートを使うことができないということ。サーバーのログインユーザーが、外部と通信するアプリケーションを勝手にインストールするなどして、管理者が知らないうちにポートが使われてしまうことを防げる。
2.は、たとえば、特定のIPアドレスから入ってきたパケットを破棄することができるということ。
3.は、特定のパケットのIPアドレスやポート番号を書き換えることができるということ。
そして、3つ目の勘違い。
Q: iptablesを使えばポートを閉じることができるよね?
A: いいえ。iptablesはポートそのものを閉じるツールではない。ポートは開いた状態のままで、ポートに入ってくるパケットを破棄することはできる。
まとめると、iptablesのメリットは、アプリケーションに到達する前のカーネルのレベル*3でパケットをフィルタリングできることである。
*1:nmapインストール方法は、「nmapの運用」のページを参考にさせていただいた。
*2:Apacheのインストール方法は、「さくらVPS設定その2 Apache+MySQL+WordPress」のページを参考にさせていただいた。
朝早く家を出ることができるアラームアプリ、MorningBombのバージョン1.0.3をリリースしました!
朝早く家を出ることができるアラームアプリ、MorningBomb(バージョン1.0.3)
Androidマーケット MorningBomb
MorningBombの公式ページ
改善点:
- 無意識にスヌーズ解除ボタン押して二度寝してしまうことを防ぐために、スヌーズ解除時には本当に解除してよいか確認するメッセージを表示するようにしました。
- 電池節約モードを作りました。
- MorningBombって何? という人のために、反省文の最後に説明ページへのURLを付けるようにしました。(Twitter投稿時のみ)
ちょっと地味ですが、実用的な機能アップだと思いますので、ぜひ使ってみてください!