さくらのVPSを契約してnginx+Node.js+MongoDBを動かすまでのメモ

従来はさくらインターネットレンタルサーバーのスタンダードプランしか契約してなくて、cgiしか動かせないのでちょっと大変だった。そこで思い切ってVPSを契約して動かしてみた。とりあえずメモ。

さくらのVPSを契約

  • CPU仮想2コア
  • メモリ1GB
  • HDD100GB
  • 月額980円(年額10,780円)

というプラン(一番安いやつ)にした。

契約後、すこし待つと、メールでrootの初期パスワードが送られてきた。

コントロールパネルに入り、マシンを起動させる。

ユーザーまわり

Macのターミナルから、

$ ssh root@(サーバーのIP)
Password: (初期パスワード)

これでつながった。

まずはrootのパスワードを自分で考えたものに変更し、さらに一般ユーザー「nacookan」を作り、これにもパスワードを設定する。 そして権限を与える。

# passwd
(rootの新しいパスワードを2度入力)

# useradd nacookan
# passwd nacookan
(nacookanの新しいパスワードを2度入力)

# usermod -G wheel nacookan
# visudo
(%wheel ALL=(ALL) ALL の行のコメントを外す)
# vi /etc/pam.d/su
(auth required pam_wheel.so use_uid の行のコメントを外す)

Macのターミナルからnacookanでつなぎなおす。

$ ssh nacookan@(サーバーのIP)
Password: (nacookanのパスワード)

そして、鍵認証の設定。ちなみに公開鍵をまだ作ってないならMac上でssh-keygenして作っておく。

$ mkdir .ssh
$ chmod 700 .ssh

$ vi .ssh/authorized_keys
(公開鍵をコピペ)
$ chmod 600 .ssh/authorized_keys

rootに切り替えて、sshdの設定

$ sudo vi /etc/ssh/sshd_config
(PermitRootLogin no と PasswordAuthentication no を追加)
$ sudo service sshd restart

nacookanの鍵でつなぎなおしてみて確認。他にも、パスワード認証ができないことと、rootでは接続できないことも確認しておく。

nginxのインストール

これはyumで入れた。簡単。

$ sudo yum install nginx

ブラウザからIPアドレスを開いてみて、なんか出ればOK。

Node.jsのインストール

nvmでやってみた。

$ git clone git://github.com/creationix/nvm.git ~/.node
$ source ~/.node/nvm.sh
$ nvm install v0.10.13
$ vi ~/.bash_profile
(source ~/.node/nvm.sh と use "v0.10.13" を追加)
$ node -v
v0.10.13

MongoDBのインストール

バイナリをダウンロードしてきて展開。

$ sudo su -
# cd /usr/local/src/
# wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.4.5.tgz
# tar zxf mongodb-linux-x86_64-2.4.5.tgz
# mv mongodb-linux-x86_64-2.4.5 /usr/local/mongodb
# ln -s /usr/local/mongodb/bin/mongo /usr/local/bin/mongo
# mkdir /data
# mkdir /data/db

MongoDBの起動は以下。

# /usr/local/mongodb/bin/mongod --logpath=/var/log/mongodb.log &

終了は kill -2 (プロセスID) で。

アプリを作ってみる

一通り入れたと思うので、さっそく動くものを作ってみる。

ドメインの設定

独自ドメインを取得して、AレコードをサーバーのIPにしておく。テスト用途でドメインが無いならローカルマシン上のhostsファイルでもいいと思う。

nginxの設定

名前ベースのバーチャルホストにするので、わかりやすいようにホスト名でconfファイルを作ってみた。置き場所は、自動的に読み込まれる設定になってるconf.dにした。

$ sudo vi /etc/nginx/conf.d/(ホスト名).conf

中身は以下のようにする。ポート80で、ホスト名にマッチしたとき、127.0.0.1:8080にproxyするような感じで。

server {
        listen 80;
        server_name (ホスト名);
        location / {
                proxy_pass http://127.0.0.1:8080;
        }
}

再起動しておく。

$ sudo service nginx restart
Node.js

準備。アプリのディレクトリを作って、npmでexpressとmongooseを入れる。

$ cd ~/
$ mkdir hello
$ cd hello
$ npm install express
$ npm install mongoose

コードを書く。

$ vi server.js

server.jsの中身は以下。

var express = require('express');
var app = express();
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/hello');

mongoose.model('Message', new mongoose.Schema({
  message: String
}));
Message = mongoose.model('Message');

app.get('/in', function(req, res, next){
  var m = new Message();
  m.message = req.query.message;
  m.save(function(err){
    res.send('OK');
  });
});

app.get('/out', function(req, res, next){
  Message.find({}, function(err, messages){
    var list = [];
    messages.forEach(function(m){
      list.push(m.message);
    });
    res.send(list);
  });
});

app.listen(8080);

モデルは、helloっていうDBの、messagesというコレクションが、messageというフィールドを持っているという感じ。/inでは、QUERY_STRINGで渡されたデータを1件登録してOKを返す。/outでは、登録されたデータを全件出力。ポートは8080。

起動しておく。

$ node server.js
MongoDB

MongoDBは、特に設定は不要。起動だけしておけばいい。

よくあるRDBMSみたいに、データベースやテーブルを事前に作っておく必要も無い。Node.jsのコードでモデルの定義をしているので勝手に作られる。

動かしてみる

ブラウザで、

http://(ドメイン)/in?message=hoge
http://(ドメイン)/in?message=fuga
http://(ドメイン)/in?message=piyo

それぞれにアクセス。いずれも「OK」と返るだけだと思う。

次に、

http://(ドメイン)/out

にアクセス。さっき登録した3つが表示されれば成功。

データベースを直接見てみる

mongoコマンドを使うと、MongoDBの中を直接操作できる。

$ mongo
> use hello
switched to db hello
> db.messages.find()
{ "message" : "hoge", "_id" : ObjectId("51e56f41d15d665a09000001"), "__v" : 0 }
{ "message" : "fuga", "_id" : ObjectId("51e56f4ad15d665a09000002"), "__v" : 0 }
{ "message" : "piyo", "_id" : ObjectId("51e56f4cd15d665a09000003"), "__v" : 0 }
> quit()

ちゃんと3つのデータが登録されている。

ここから追記

追加で以下の作業をやった。

コンソールを日本語に

manとかでヘルプを見た時に日本語で出たほうがうれしいので、コンソールを日本語にしておく。

$ sudo vi /etc/sysconfig/i18n
(LANG="C" をコメントにして、LANG="ja_JP.UTF-8" を追加)

一度ログアウトしてログインしなおす。

SSHのポートを変更

22のままだと攻撃がたくさん来てしまう。鍵認証にしてるからセキュリティ的には特に問題なくても、サーバーへの負荷という意味で困るので、ポートを変えておく。

$ sudo vi /etc/ssh/sshd_config
(Port 22222を追加)
$ sudo service sshd restart

22222というのは適当に書いた。マネしない方がいいし、自分も実際は違う番号にしている。各自が1024〜65535の間の好きな番号にすればいい。

他とかぶらない番号にする(たとえば8080とかは避ける)ことと、自分で設定した番号を忘れないようにするのが重要。

設定を変えたら確認してみる。Macのターミナルから、

$ ssh nacookan@(サーバーのIP) -p 22222 -i 鍵のパス

こんな風にしてつなぐ。

iptables

iptablesはデフォルトでは全開放の状態らしい。とりあえず今回は、上記で許可したSSHのポートと、HTTPの80番だけを許可するようにする。

$ sudo vi /etc/sysconfig/iptables

最初はファイルがないので新規作成。内容は以下。

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:RH-Firewall-1-INPUT - [0:0]
-A INPUT -j RH-Firewall-1-INPUT
-A FORWARD -j RH-Firewall-1-INPUT

-A RH-Firewall-1-INPUT -i lo -j ACCEPT
-A RH-Firewall-1-INPUT -p icmp --icmp-type any -j ACCEPT
-A RH-Firewall-1-INPUT -p 50 -j ACCEPT
-A RH-Firewall-1-INPUT -p 51 -j ACCEPT
-A RH-Firewall-1-INPUT -p udp --dport 5353 -d 224.0.0.251 -j ACCEPT
-A RH-Firewall-1-INPUT -p udp -m udp --dport 631 -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp -m tcp --dport 631 -j ACCEPT

-A RH-Firewall-1-INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 22222 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT

-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited

COMMIT

正直よくわからないんだけど、たぶんスタンダードな設定のはず。

  • INPUTとFORWARDを「RH-Firewall-1-INPUT」というところに流して(名前はなんでもいい)、以降はRH-Firewall-1-INPUTに対する設定としている
  • lo(ループバック)を許可
  • icmpを許可
  • プロトコル番号50と51を許可(よくわからないけどみんなやってるのでマネした)
  • マルチキャストDNSを許可
  • TCPUDPの631番、プリンタの通信を許可(これは無くてもいい気がする)
  • stateモジュールを使う
  • 新規接続の22222を許可(SSHのポートね)
  • 新規接続の80を許可(HTTPのポートね)
  • それ以外は拒否

こんな感じの意味だと思う。

sudo service iptables restart

これで新しい設定が反映される。

アップデート

インストールされているもろもろについて、最新版の状態に更新しておく。

$ sudo yum --security update

やってみたけど、自分の場合は特に更新はなかった。さくらのVPSは最新版が入った状態で提供されてるってことかな。今後、定期的にこれを実行して最新版を維持する必要がある。自動更新する仕組み等もあるらしいけど試してない。

ちなみにセキュリティ関連だけじゃなく、すべてのパッケージのアップデートをしたいなら、--securityを外せばいい。

追記ここまで

これで一通りやることはやった気がする。

簡単だった

ここまで、とくに問題なくできたのでよかった。今後はこのVPSを使って、ちょっとしたものを作っていきたい。

間違ってるところとかあったら教えてください。