node.jsからリモートサーバーのmongoDBに接続する方法


node.jsで開発をする時、開発環境と本番環境では別のデータベースを使っていませんか？
![スクリーンショット 2014-07-23 15.37.55.png](https://qiita-image-store.s3.amazonaws.com/0/4784/51d37e5e-67d0-0fb8-d11a-07057ef3a7f9.png)
この場合、ローカルでデータを更新しながら開発して、いざ本番環境で動作をテストする時に１からまたデータを追加更新しなければいけません。
なので開発時もデータベースだけはリモートサーバーのものを使いたいと思い、このエントリを書きました。

![スクリーンショット 2014-07-23 15.38.05.png](https://qiita-image-store.s3.amazonaws.com/0/4784/0bc1b2e7-1353-4a9b-8f27-b240cc8e5a1e.png)

リモートサーバーの環境はさくらVPS+centOSです。

## <a name='main'>リモートサーバーのmongoDBに接続する方法(node.js)</a>

ドライバは
[Node.JS MongoDB Driver](http://mongodb.github.io/node-mongodb-native/contents.html)
を使います。  

`npm install mongodb`  

でインストールできます。

以下はnode.jsからmongoDBに接続するコードです。

```coffee:app.coffee
mongo = require("mongodb")
Server = require('mongodb').Server
Db = mongo.Db
BSON = mongo.BSONPure
assert = require('assert')

db = new Db('db1', new Server('xxx.xx.xx.xx', 27017),{safe:false})
db.open (err, db)->
  if err
    log err
  else
    db.collectionNames (err, items)->
      assert items.length > 0
```
localのDBに接続する時は`127.0.0.1`と設定するところをリモートサーバーの
IPアドレスに書き換えただけで接続できました。


あれ？  
もしかして？  
これって誰からもアクセスできちゃうんじゃね？？？




改めて調べてみると、mongoDBは初期状態だと外部からのアクセスはオールOKです。
ザルです。

## mongoDBのセキュリティを見直す

ザルだとわかった所でなんとかしましょう。  
MySQL等では最初にアクセス権のあるユーザーを設定します。  
そしてRootでのアクセスを禁止してセキュリティを高めます。  
MongoDBでも同じような設定ができます。

### 1.管理者(admin)の設定
mongoシェルを起動して以下を入力します

```
> use admin
switched to db admin
> db.addUser('user1','password')
{
	"user" : "user1",
	"readOnly" : false,
	"pwd" : "e7e8a26d330dbb8bef5b1886ceb5e290",
	"_id" : ObjectId("53cdf6cf3baadf71b7b2a006")
}
```
adminコレクションに`addUser('ユーザー名','パスワード')`
というコマンドで設定できます。
現時点では認証設定が無効ですが、
有効化した後では管理者としてログインしていないとユーザーの追加はできません。

### 2.使用するDBでユーザーを設定

```
> use db1
switched to db db1
> db.addUser('user1','password')
{
	"user" : "user1",
	"readOnly" : false,
	"pwd" : "e7e8a26d330dbb8bef5b1886ceb5e290",
	"_id" : ObjectId("53cdf8d0b31d6d88862bae5e")
}
```
これで「db1」というデータベースにアクセスできる「user1」を設定しました。

### 3.認証を有効化する
`/etc/mongod.conf`に設定ファイルがあるので書き換えます。

```
% sudo vim /etc/mongod.conf
```
26行目くらいに
`#auth = true`とあるのでこのコメントを外してauthを有効にします

```vim
#auth = true
↓
auth = true
```
esc - :wqで保存して設定は完了です。
mongodを再起動します。

```
% sudo service mongod restart
```

### 4.mongoシェルでDBにアクセスする。

mongoシェルを開き、`use db1`してから
show collectionsでコレクションの一覧を取得してみましょう。

```
> show collections
Tue Jul 22 14:53:01.657 error: {
	"$err" : "not authorized for query on db1.system.namespaces",
	"code" : 16550
} at src/mongo/shell/query.js:128
```
認証設定が有効になっていたら失敗するはずです。
ログインしてみましょう。
`db.auth('ユーザー名','パスワード')`でログインできます。  
続けて再度show collectionｓすると取得できるはずです。

```
> db.auth('user1','password')
1
> show collections
system.indexes
system.users
>

```

または、mongoシェルを開く時にユーザーとパスワードを入力することもできます。

```
% mongo 127.0.0.1:27017/db1 -u user1 -p password
MongoDB shell version: 2.4.10
connecting to: 127.0.0.1:27017/db1
> show collections
system.indexes
system.users
```


### 5.localからnode.jsでリモートサーバーのDBにアクセスする
ここまでの作業はsshでサーバーにログインして作業していましたが、
以下はlocalから直接サーバーのmongoDBにアクセスする方法です。
冒頭の[リモートサーバーのmongoDBに接続する方法(node.js)](#main)をそのまま試してみましょう。


>{ [MongoError: not authorized for query on db1.system.namespaces]
>  [stack]: [Getter/Setter],
>  [arguments]: undefined,
>  [type]: undefined,
>  [message]: 'not authorized for query on db1.system.namespaces',
>  name: 'MongoError' }

ログインしていないのでエラーになりました。

`db.authenticate('ユーザー名', 'パスワード',コールバック関数(err, result))`

でログインできます。
成功ならresultに1が返ります。

```coffee:app.coffee
db = new Db('db1', new Server('xxx.xxx.xx.xx', 27017),{safe:false})
    db.open (err, db)->
      if err
        log err
      else
        db.authenticate 'user1', 'password', (err, result)->
          if err
            log err
          else
            db.collectionNames (err, items)->
              if err
                log err
              else
                assert items.length > 0
                log items
```


### まとめ
##### 管理者設定
```
> use admin
> db.addUser('user1','password')
```
##### DBごとの接続ユーザー設定
```
> use db1
> db.addUser('user1','password')
```
##### /etc/mongod.confを設定
```
#auth = true
↓
auth = true
```

##### mongoシェルでログイン
```
db.auth('user1','password')
または
mongo 127.0.0.1:27017/db1 -u user1 -p password
```
##### node.jsでログイン 

```coffee
db.authenticate 'user1', 'password', (err, result)->
```

以上です。