Realm Object ServerでATS対応したい

[Realm Advent Calendar 2016](http://qiita.com/advent-calendar/2016/realm)の22日目の[かっくん](http://qiita.com/fromkk)です。
[3日目](http://qiita.com/fromkk/items/159213221e3b50ce50bc)に引き続きの投稿です。

昨日の[Realm meetup 忘年会 + LT大会 2016](https://realm.connpass.com/event/46269/)にて発表した内容を記事にしておきたかったのでAdvent Calendarにも投稿したいと思います。

---

僕は[Realm Mobile Platform](https://realm.io/products/realm-mobile-platform/)が発表された頃から興味を持ち始めて少しずつ調べていました。
自社の[ブログ](http://techblog.timers-inc.com/entry/realm_mobile_platform)や[イベント](http://techblog.timers-inc.com/entry/firebase_ebisu_1)で[紹介](https://speakerdeck.com/fromkk/try-realm-mobile-platform)する等して少しでも広まれば良いなと思っていました。

しかし、そんな折に大きな障壁が僕の前に立ちはだかりました。
まずはこちらをご覧ください。

<img src="https://qiita-image-store.s3.amazonaws.com/0/2846/6877f5b2-debd-2c8d-7b35-f30ac054ba8c.png" width="480" height="auto" alt="Document" />

Realm SwiftのドキュメントのRealm Mobile Platformに関する[サンプルコード](https://realm.io/docs/swift/latest/#users)ですが、

<img src="https://qiita-image-store.s3.amazonaws.com/0/2846/b4113399-4fe2-6eb7-9607-01b1911419f0.png" width="480" height="auto" alt="http" />

見事に **http** ですね。

そうです、障壁とは年末にやってくるこれですね。

![ats](https://qiita-image-store.s3.amazonaws.com/0/2846/8b5fc35f-ebde-8594-94bf-a2eb7aef9888.png)

という事で、普段はiOSエンジニアをやっている僕がRealm Mobile PlatformをSSLで通信出来る様にした事を共有出来ればと思います。

---

# 環境

- Sakura VPS
- CentOS 7
- Nginx(proxy)
- Let's Encrypt
- Realm Object Server

## 前提

Let's encryptを使用するのでドメインが必要です。
ドメインのネームサーバー等の設定が済んでおり、ドメインがVPSのIPに向いている事を前提とします。
（この辺がいきなりハードル高いかも...）
**※記事の中にyourdomain.comと表記されている所は適宜書き換えて下さい**

## 初期設定

とりあえずの環境構築なので初期設定状態からrootでログインしたまま始めます。
**※本来はログイン専用のユーザーを作ってSSHのポート変更をまずやるべきですがここでは省略します。**

## Firewallの設定を変更

CentOS 7から `iptables` ではなく `firewall` になってたんですね。
必要なポートのみ開けておきます。

```bash
firewall-cmd --add-service=http --zone=public --permanent
firewall-cmd --add-service=https --zone=public --permanent
firewall-cmd --permanent --add-port=9080/tcp --permanent
firewall-cmd --reload
```

## Realm Object Server のインストール

こちらはドキュメントにそってインストールします。

```bash
# Setup Realm's PackageCloud repository
curl -s https://packagecloud.io/install/repositories/realm/realm/script.rpm.sh | sudo bash

# Install the Realm Object Server
sudo yum -y install realm-object-server-de

# Enable and start the service
sudo systemctl enable realm-object-server
sudo systemctl start realm-object-server
```

## 一旦通常のDashboardを開いてみる

http://yourdomain.com:9080/ にアクセスして

<img src="https://qiita-image-store.s3.amazonaws.com/0/2846/0eaf2b77-07ef-0623-42a6-0a258bd5cf3f.png" width="480" height="auto" alt="Registration" />

と新規登録画面が表示される事を確認します。

## Nginxのインストール

```bash
rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
yum -y update nginx-release-centos
yum -y --enablerepo=nginx install nginx
```

### Nginx の設定を変更して **http** でプロキシを利用する

**/etc/nginx/conf.d/default.conf** を下記の様に編集します。

```
server {
    listen 80;

    server_name _;

    location / {
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   Host      $http_host;
        proxy_pass         http://127.0.0.1:9080;
    }
}
```

これでNginxを起動します。

```bash
systemctl start nginx
```

### **http** でのアクセスを確認

http://yourdomain.com/ でアクセス（ポート9080を削除）して先程と同様にRealmの管理者新規登録ページが表示される事を確認します。

# Let's Encrypt

80ポートでのアクセスが確認出来れば次はSSL化です。
2016年4月より本番運用されている[Let's Encrypt](https://letsencrypt.jp/)を利用します。

## インストール


```bash
cd /opt
git clone https://github.com/certbot/certbot
cd ./certbot
./certbot-auto certonly --standalone -d yourdomain.com
```

必要なライブラリのインストールが始まり、途中でメールアドレスの入力と規約の同意が求められます。

<img width="480" alt="install11.png" src="https://qiita-image-store.s3.amazonaws.com/0/2846/29b119bd-db5b-3986-11b6-93f165b10da2.png">

という画面と、

```
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/yourdomain.com/fullchain.pem. Your cert will
   expire on 2017-03-03. To obtain a new or tweaked version of this
   certificate in the future, simply run certbot-auto again. To
   non-interactively renew *all* of your certificates, run
   "certbot-auto renew"
 - If you lose your account credentials, you can recover through
   e-mails sent to youremail@domain.com.
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
```

というログが表示されればインストール完了です。

## Nginxの設定

先程のログに証明書の保存場所が記載されているのでそれを利用してNginxの設定を書き換えます。

/etc/nginx/conf.d/default.conf

```diff
server {
    listen 443 ssl;
    server_name yourdomain.com;
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.com/chain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE+RSAGCM:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!aNULL!eNull:!EXPORT:!DES:!3DES:!MD5:!DSS;
    ssl_prefer_server_ciphers on;

    ssl_stapling on;
    ssl_stapling_verify on;

    location / {
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   Host      $http_host;
        proxy_pass         http://127.0.0.1:9080;
    }
}
```

Nginxの再起動を行います。

```bash
systemctl restart nginx
```

## **https**でのアクセスの確認

https://yourdomain.com/

![login4.png](https://qiita-image-store.s3.amazonaws.com/0/2846/2228ab71-8f45-395d-a3ed-defa637ac468.png)

無事**https**でアクセスが出来ましたでしょうか？

念のため、新規登録やログインが正しく出来る事を確認しましょう。

> と、ここまでNginxをプロキシとして利用していましたが、Realm Object Server自体がプロキシ機能を持っているので本来は必要無いはずなんですよね...[参照](https://realm.io/docs/realm-object-server/#network)
> ただ、**/etc/realm/configuration.yml**を変更してRealm Object Serverを再起動するとダッシュボードすら開かなくなってしまったので今回はNginxでの設定にしました。
> どなたか、**configuration.yml**での設定方法をご存知ならご教授下さいm(_ _)m

---

# Realm Swiftの初期設定部分のコードも修正します

これまで **http** と書いていた箇所を **https** にしてポート番号を削除、もしくは、443ポートに変更します。

```swift
import Realm
import RealmSwift

let credential: SyncCredentials = SyncCredentials.usernamePassword(username: "YOUR USER NAME",
                                                                   password: "YOUR PASSWORD")
SyncUser.logIn(with: credential,
             server: URL(string: "https://yourdomain.com/")!,
       onCompletion: { [weak self] (user, error) in
    if let user = user {
        let configuration = Realm.Configuration(syncConfiguration:
          SyncConfiguration(user: user, realmURL: URL(string: "realm://yourdomain.com:9080/~/realm")!))
        Realm.Configuration.defaultConfiguration = configuration
        //write your code!
    } else if let error = error {
        print("login failed \(error)")
    }
})
```

**realm**スキームはそのままでも問題無さそうだったので変更はしていません。

あ、**Info.plist**のATSの設定も削除してしまいましょう。

```diff
- <key>NSAppTransportSecurity</key>
- <dict>
- 	<key>NSAllowsArbitraryLoads</key>
- 	<true/>
- </dict>
```

無事、アプリも正しく動く事を確認しましょう。
Realm Browserを利用すればリアルタイム同期がちゃんと動作している事を確認出来ます。

---

# まとめ

なんとかRealm Mobile PlatformをHTTPSで接続する事に成功しました。iOSアプリを作成するのにATS対応は今後大きな障壁になりそうですが、Let's Encryptを利用すればその問題も解決出来ます。
せっかく新しく出てきたPlatformなのにちょっとした障壁のせいで利用を諦めてしまうのも勿体無いので、これを機に2017年に向けて開発の準備を進めていきましょう！