EC2用Python APIサーバーのサンプルイメージ（パブリックAMI）

PythonでAPIサーバー作るときの自分用のAMIについてメモ。
バックドアとか仕込まれてたら嫌だから、他人が使うことは無いだろうけど、もし使われる方がいれば自己責任でお願い致します。

ダメな設定とかあれば、ご指摘いただけたら幸いです。

nginx、[gunicorn](http://gunicorn.org/)を入れてる。

大雑把には、gunicornを[Upstart](https://ja.wikipedia.org/wiki/Upstart)使って8000ポートで立ち上げといて、nginxでリバースプロキシする感じ。

開発用サーバーとして複数のプロジェクトをホスティングするのを想定して作ってて、各プロジェクト用のフォルダ構成は以下の通り。

```text
/home/www/
└── somedomain
    ├── api_server
    │   ├── virtualenv
    │   ├── pip.txt
    │   └── python
    │       └── server.py
    └── web
        └── htdocs
            └── index.html
```

`www`は*nginx*やAPIサーバーを実行してるユーザー。
プロジェクトごとに`somedomain`フォルダが増えていく感じ。

# サーバーの立ち上げ方

公開してるAMIのIDは、`ami-24486d4a`。
間違って違うAMIを入れないようにしないと。

EC2のコンソールを開く。

左のメニューのAMIをクリックして、イメージの検索バーを*パブリックイメージ*にして、検索フィールドに`ami-24486d4a`を入れたらイメージが出てくる。

右クリックで起動する。


# インストールしたもの

## yumにて

- nginx
- git


# 設定

いじったファイルは以下の通り。

## Webサーバーの設定（nginx）

### サーバー本体の設定

```nginx:/etc/nginx/nginx.conf
user  www;
worker_processes  auto;

error_log  /var/log/nginx/error.log;

pid        /var/run/nginx.pid;


events {
    worker_connections 1024;
}

http {
    include         /etc/nginx/mime.types;
    default_type    application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;

    keepalive_timeout   65;
    types_hash_max_size 2048;

    include /etc/nginx/conf.d/*.conf;

    index   index.html index.htm;

}
```

レスポンスにサーバーのバージョンが入っちゃうオプションを消し忘れてたので、この設定をhttpディレクティブの中に追加。

```nginx
    server_tokens off;
```

修正が溜まったら、AMIを更新しよう。

### バーチャルホストの設定

[CloudFlare](https://www.cloudflare.com/)使ってても、元IPが変わんないようにする設定入れてる。
詳しくは、[こちら](https://support.cloudflare.com/hc/en-us/articles/200170706-How-do-I-restore-original-visitor-IP-with-Nginx-)。

`__pull_from_bitbucket`は、[Bitbucketとデプロイ連携する](http://qiita.com/polikeiji/items/fc6f9bbe7a619a053319)ときに、アクセス元を*Bitbucket*のIPで絞ってる。
Bitbucketを使わない時は、消す。

```nginx:/etc/nginx/conf.d/somedomain.conf
upstream somedomain_api_server {
    server 127.0.0.1:8000 fail_timeout=0;
}

server {
    listen       80;
    server_name  somedomain;
    root         /home/www/somedomain/web/htdocs;

    #charset koi8-r;

    # for CloudFlare
    set_real_ip_from 199.27.128.0/21;
    set_real_ip_from 173.245.48.0/20;
    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    set_real_ip_from 103.31.4.0/22;
    set_real_ip_from 141.101.64.0/18;
    set_real_ip_from 108.162.192.0/18;
    set_real_ip_from 190.93.240.0/20;
    set_real_ip_from 188.114.96.0/20; 
    set_real_ip_from 197.234.240.0/22;
    set_real_ip_from 198.41.128.0/17;
    set_real_ip_from 162.158.0.0/15;
    set_real_ip_from 104.16.0.0/12;
    set_real_ip_from 172.64.0.0/13;
    set_real_ip_from 2400:cb00::/32;
    set_real_ip_from 2606:4700::/32;
    set_real_ip_from 2803:f800::/32;
    set_real_ip_from 2405:b500::/32;
    set_real_ip_from 2405:8100::/32;
    real_ip_header CF-Connecting-IP;

    access_log  /var/log/nginx/somedomain.access.log  main;

    location /__pull_from_bitbucket {
        satisfy any;
        allow 131.103.20.160/27;
        allow 165.254.145.0/26;
        allow 104.192.143.0/24;
        allow 220.156.98.58/32;
        deny all;

        try_files $uri $uri/ @proxy_to_app;
    }

    location / {
        try_files $uri $uri/ @proxy_to_app;

        add_header Cache-Tag main;
    }

    location @proxy_to_app {
        satisfy any;

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        #proxy_buffering off;
        proxy_pass   http://somedomain_api_server;
    } 
}
```

## APIサーバーの設定（Upstartでgunicorn）

*www*ユーザーでAPIサーバー用の*virtualenv*環境に*gunicorn*を入れてる。

GITHUB_HOOK_SECRETは、[GitHubとデプロイ連携する](http://qiita.com/polikeiji/items/fc6f9bbe7a619a053319)時に、使う環境変数。
GitHub使わない時は、消す。


```bash:/etc/init/somedomain-api-server.conf
description "Somedomain API Server"

start on runlevel [2345]
stop on runlevel [016]

# GitHub Hook Secret
env GITHUB_HOOK_SECRET=""

respawn
exec /home/www/somedomain/api_server/virtualenv/bin/gunicorn -b 127.0.0.1:8000 -w 4 -u www --chdir /home/www/somedomain/api_server/python --log-file /home/www/somedomain/api_server/logs/error_log --pythonpath /home/www/somedomain/api_server/python server:application
```

## サンプルアプリ

*www*ユーザーの`/home/www/somedomain`においてる。

静的コンテンツ用のフォルダは`web`、Python用のフォルダは`api_server`にしてる。
*virtualenv*は、`api_server/virtualenv`に入れてる。


# サーバーの起動、停止

## nginxの起動／停止

```bash
# 起動
sudo /etc/init.d/nginx start

# 停止
sudo /etc/init.d/nginx stop

# 再起動
sudo /etc/init.d/nginx restart
```

## gunicornの起動／停止

```bash
# 起動
sudo start somedomain-api-server

# 停止
sudo stop somedomain-api-server

# 再起動
sudo restart somedomain-api-server
```


# バーチャルホストの追加手順

1. wwwユーザーになってプロジェクト用のフォルダを作って、PythonとかWebのファイルを置く。
2. APIサーバーの設定をする。（[参考](http://qiita.com/polikeiji/items/51052ab6df169287a922#api%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%AE%E8%A8%AD%E5%AE%9Aupstart%E3%81%A7gunicorn)）
3. Webサーバーの設定をする。（[参考](http://qiita.com/polikeiji/items/51052ab6df169287a922#web%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%AE%E8%A8%AD%E5%AE%9Anginx)）
4. 必要に応じてGitHub、Bitbucketのデプロイ連携の設定をする。