PeeeeRONの日記

更新頻度はあまり高くはありませんがネタがあったら書いていこうと思います。

docker-composeでLet's Encrypt SSL,HTTP2通信対応Nginxリバースプロキシサーバを構築する

お久しぶりです。

最近CoreOSのサーバを構築しました。WebサーバとしてNginxを動かしたのですが、docker-composeを使った方法がすごく簡単にLet's Encryptを使ったSSL対応のNginxを動かせたので皆さんにも使っていただきたく記事にしました。

Let's Encryptは無料のSSL証明書で簡単にサーバをSSL対応できますが、証明書の更新をcronに登録したり、ドメインごとに設定しなければならず少し面倒でした。しかし、Dockerを使えば自動的にこれらの作業を行わせることができます。Nginxの設定を自らいじる必要もありませんでした。

それでは、手順を紹介したいと思います。

リポジトリのクローン

まずこちらオープンソースをクローンします。

git clone https://github.com/evertramos/docker-compose-letsencrypt-nginx-proxy-companion.git

以下のdocker-compose.ymlが今回利用するものです。

version: '3'
services:
  nginx:
    image: nginx
    labels:
        com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: "true"
    container_name: nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ${NGINX_FILES_PATH}/conf.d:/etc/nginx/conf.d
      - ${NGINX_FILES_PATH}/vhost.d:/etc/nginx/vhost.d
      - ${NGINX_FILES_PATH}/html:/usr/share/nginx/html
      - ${NGINX_FILES_PATH}/certs:/etc/nginx/certs:ro

  nginx-gen:
    image: jwilder/docker-gen
    command: -notify-sighup nginx -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
    container_name: nginx-gen
    restart: unless-stopped
    volumes:
      - ${NGINX_FILES_PATH}/conf.d:/etc/nginx/conf.d
      - ${NGINX_FILES_PATH}/vhost.d:/etc/nginx/vhost.d
      - ${NGINX_FILES_PATH}/html:/usr/share/nginx/html
      - ${NGINX_FILES_PATH}/certs:/etc/nginx/certs:ro
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro

  nginx-letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: nginx-letsencrypt
    restart: unless-stopped
    volumes:
      - ${NGINX_FILES_PATH}/conf.d:/etc/nginx/conf.d
      - ${NGINX_FILES_PATH}/vhost.d:/etc/nginx/vhost.d
      - ${NGINX_FILES_PATH}/html:/usr/share/nginx/html
      - ${NGINX_FILES_PATH}/certs:/etc/nginx/certs:rw
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      NGINX_DOCKER_GEN_CONTAINER: "nginx-gen"
      NGINX_PROXY_CONTAINER: "nginx"

networks:
  default:
    external:
      name: webproxy

必要であれば、編集してください。
自分は使っているdocker-composeがバージョン3に対応していなかったので、version: "2"にして、CoreOSは自動アップデートのときに再起動を行うので、restart: unless-stoppedrestart: alwaysに変更しました。

Dockerネットワークの作成

次にnetworkを作成します。

docker network create webproxy

設定ファイルの用意

.envファイルを用意する。 docker-compose.ymlと同じディレクトリに以下の内容の.envファイルを用意します。

NGINX_FILES_PATH=/path/to/your/nginx/data

これはdocker-compose.ymlの環境変数を設定するためです。このパスにはnginxの設定ファイル等が保存されます。

コンテナ起動

コンテナの起動 コマンドを入力してコンテナを起動しましょう。

docker-compose up -d

これでLet's EncryptによるSSL対応のNginxリバースプロキシサーバの起動できました。このコンテナでは証明書の自動更新なども行ってくれるので自分で設定する必要はありません。

ブラウザでサーバにアクセスするとNginxの503エラーページが表示されるはずです。

アプリケーションサーバの用意

次に動かしたいWebアプリのサーバを作成します。 こちらもdocker-composeで動かすようにします。Dockerfileはご自分で作成してください。注意点としては80番と443番のポートをEXPOSEしてください。あとAPPサーバは80番、または443番をListenするようにしてください。

EXPOSE 80 443

そして起動するためのdocker-composeファイルを作成します。例えば以下のように作成します。アプリに応じてDBサーバの設定などを書いてもいいです。

version: "2"
services:
  app:
    build: .
    command: /app
    environment:
      - VIRTUAL_HOST=example.com
      - LETSENCRYPT_HOST=example.com
      - LETSENCRYPT_EMAIL=example@example.com
    restart: always

networks:
  default:
    external:
      name: webproxy

必ず設定しなければならないのは、環境変数VIRTUAL_HOST,LETSENCRYPT_HOST,LETSENCRYPT_EMAILと、Docker ネットワークの設定だけです。

アプリケーションサーバの起動

docker-compose up -d

アプリケーションサーバを起動すると、自動的に先程起動したNginxコンテナが起動を検知しLet's Encryptの証明書を取得し、Nginxの設定ファイルを生成します。これは先程設定したNginxの設定ファイルのディレクトリを見ればわかります。

しばらくまって、ブラウザでドメインにアクセスするとSSL通信できるようになっています。

まとめ

以上でNginxのSSL対応リバースプロキシサーバとアプリケーションサーバが構築できました。また別のサービスを立ち上げた時は、docker-composeファイルを作れば、リバースプロキシやSSLの設定は自動的に行なってくれるのでとても簡単です。是非使ってみてください。

追記

ちなみに通信はHTTP2になるようです。

コマンドの終了をSlackに通知するコマンドを作った。

コマンドの終了をSlackへの投稿で知らせるコマンドを作りました。DeepLearning等の機械学習の学習はとても時間がかかり、GPUを使っても数時間かかるのが当たり前なので終了通知を何らかの方法でうけとりたい。そこでSlackでその通知を受け取れるようにした。

使い方は簡単、まずホームディレクトリに.exslackrcというファイルを作成し以下のように書き出す。

{
  "webHookURL": "https://hooks.slack.com/services/X..../Y....",
  "destination": "@rompei",
  "logFile": "/home/rompei/joblog.txt"
}

webHookURLはSlackのincoming-webhookのURLで、destinationは通知したいユーザかチャンネル。もしコマンドの出力が必要ならlogFileを設定すればコマンドの出力をそのファイルに出力してくれる。またlogFileコマンドラインオプションの-logでも設定できる。

そして実行しいコマンドが並んだファイルを作成する。

./test1.sh xyz
./test2.sh abc

あとはコマンドの並んだファイルを引数にして実行するだけ。

Command ./test1.sh started on 2016-06-26 15:16:19.363573005 +0900 JST is done in 5.61877ms

Command ./test2.sh started on 2016-06-26 15:16:20.761145297 +0900 JST is done in 10.125984ms

このような感じでSlackに通知が来る。
また、ログファイルを設定すると

exslack: 2016/06/26 15:16:19 Command ./test1.sh started on 2016-06-26 15:16:19.363573005 +0900 JST is done in 5.61877ms

 == Output start == 

test1 test1arg1


 == Output end == 

exslack: 2016/06/26 15:16:20 Command ./test2.sh started on 2016-06-26 15:16:20.761145297 +0900 JST is done in 10.125984ms

 == Output start == 

test2 test2arg1


 == Output end == 

こんな感じで出力を確認ファイルから確認できる。

github.com

ディープラーニングで画像を超解像するwaifu2xをGoで実装してみた。

Web+DBとい雑誌で少し前にディープラーニング入門の記事があったので読んでいたら、waifu2xというディープラーニングの技術を使って画像の解像度を上げるソフトウェアがあることを知りました。

このソフトウェアの様々な言語での実装ができていたので、今回はGoで実装してみることにしました。実装した部分は学習済みモデルを使って画像の解像度を上げる部分です。

参考にしたプログラムはPythonで書かれているこれを使わせて頂きました。ただ本家と1つだけ違うのは畳み込みではなく自己相関関数を使いました。これが利用したモデルです。本家のLuaで書かれたwaifu2xを使うと新しいモデルを作れるみたいです。このモデルは本家のものとニューラルネットの形状が若干違っていて、最初の入力が本家のものはRBG(三原色)の3チャネルなのに対し、Python実装のものはY(輝度)の1チャネルになっていました。

Pythonと違い数値計算ライブラリが発展途上のGoなので結構たいへんでした。行列演算にはgonum/matrixというGoogle製のオープンソースを使いました。
画像は本家のものと同じmiku_small.pngを使い。

f:id:PeeeeRON:20160223182525p:plain

これを2倍に拡大しました。
まずは普通に近傍補完法で拡大した画像がこちらです。

f:id:PeeeeRON:20160223182652p:plain

明らかにジャギっています。
次にwaifu2xで拡大したものです。

f:id:PeeeeRON:20160223182745p:plain

若干縁のギザギザが小さくなっているのが分かります。
なぜか保存してみると画像が左上に移動してしまっていますが、超解像に成功しています。
コードはGithubにあります。

github.com

画像が左上のずれるバグが直っていないので、プルリク送って頂けると助かります。

Raspberry pi 2にNginx+GolangでWebサーバー構築

NginxとGolangで自宅Webサーバ環境を構築したので、その方法を書きたいと思います。

http://hardikdabhi.com/blog/automation-boards/img/raspberrypi-logo.png https://avatars2.githubusercontent.com/u/1412239?v=3&s=200 https://techstars.jp/blog/wp-content/uploads/2015/10/gopher_head.png

環境

Linux raspberrypi 4.1.17-v7+ #838 SMP Tue Feb 9 13:15:09 GMT 2016 armv7l GNU/Linux
nginx version: nginx/1.6.2

Raspbianインストールからセキュリティ設定

ココらへんは他のサイトに書かれているのでそれらを参考してください。
インストール時の注意点としてはWebサーバ用途であればGUIは必要ないのでRaspbian LITEで良いです。あと、IPアドレスですが、ルータの設定ページにどこからどこまでをプライベートIPとして使うとか書かれているので下からpingしていけばOKです。pingできればssh pi@[ip-address]で接続してパスワードはraspberryです。通ればほぼ確でラズパイです。

セキュリティ設定は

Raspberry Piのセキュリティー設定 for Webサーバー用 パート1 | ものづくりエクスペリメント

Raspberry Piのセキュリティー設定 for Webサーバー用 パート2 | ものづくりエクスペリメント

を参考にしてください。

Nginx導入

RaspbianのパッケージにあるNginxは1.6.2です。安定版は1.8ですがソースからビルドしたところセグメンテーションフォールトでクラッシュしてしまったので、仕方なく1.6.2を使いました。

ここからの過程はroot権限が必要なのでrootでなければsudoをつけてください。

apt-get update
apt-get upgrade
apt-get install nginx

でインストールします。

Nginxの設定ファイルは/etc/nginx以下にあります。設定しなければならないものは/etc/nginx/nginx.conf/etc/nginx/sites-available/[server-name]です。設定ファイルはホームディレクトリなどにバックアップをとっておくと良いです。
/etc/nginx/nginx.confは好みですが自分はserver_tokens off;gzip on;にしました。

/etc/nginx/sites-available/[server-name]にはバーチャルホストの設定をします。自分は下記のように設定しました。

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    server_name [server-name];

    root /var/www/html/[プロジェクトネーム];
    index index.html;

    location / {
        try_files $uri $uri/ =404;
        proxy_pass http://127.0.0.1:[ポート番号];
    }
    location ~ .*\.(jpg|JPG|gif|GIF|png|PNG|swf|SWF|css|CSS|js|JS|inc|INC|ico|ICO) {
        root    /var/www/html/[プロジェクトネーム]/public;
    }
}

サーバネーム、パスやポート等は自分の環境にしてください。ポート番号は環境変数で設定すると便利です。
ルートにアクセスした時デフォルトで表示するサイトの設定ファイルにはlistenの最後にdefault-serverを追記します。はじめから入っている/etc/nginx/sites-available/defaultdefault-serverは消してください。この設定の場合Goの実行ファイルは/var/www/html/[プロジェクトネーム]以下に静的ファイルは/var/www/html/[プロジェクトネーム]/public以下に配置します。location /にあるproxy_passはこのバーチャルホストの/にきたアクセスはhttp://127.0.0.1:[ポート番号]に転送してくださいという意味です。もし別のマシンでGoのWebサーバを動かす場合はIPアドレスを変更します。その下のlocation ~ .*\.(jpg....は静的ファイルの保存場所を表しています。

記述完了したら保存して/etc/nginx/sites-enabled以下にシムリンクを貼ります。

ln -s /etc/nginx/sites-available/[プロジェクトネーム] /etc/nginx/sites-enabled/[プロジェクトネーム]

これで設定が有効化されます。そしたら

nginx -t

で設定ファイルの正しさを検証します。

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

とでたらOKです。

そしたら下記コマンドでNginxを再起動します。

nginx -s reload

これでNginxの設定が完了しました。

ルータの設定

Webサーバを公開するにあたりルータの80番ポートにきた通信をラズパイに転送する設定をします。ルータのプライベートIPアドレスにアクセスし設定画面を開きます。まずラズパイのマックアドレスに対するプライベートIPアドレスを固定してください。そしたら80番ポートをラズパイのプライベートIPアドレスマッピングしてください。これでルータの80番ポートの通信がラズパイに転送されます。

GoのWebサーバの導入

Goはクロスコンパイル可能なコンパイル型言語なのでラズパイ上にビルド環境を作成する必要はありません。作成してもいいですが、セキュリティを高めたければ作らないほうがいいです。クロスコンパイルには

GitHub - mitchellh/gox: A dead simple, no frills Go cross compile tool

を使います。

go get -u https://github.com/mitchellh/gox

で開発マシンにインストールしてください。

gox osarch="linux/arm"

でラズパイで動くバイナリを生成できます。

バイナリを生成したらscpコマンドなりsftpなりで設定ファイルで指定した場所に実行ファイル、静的ファイル群を転送します。最後に

cd [実行ファイルのあるパス]
./[プロジェクトネーム] &

でセットアップ完了です。

LAN内で[ラズパイのプライベートIP]、LAN外部から[自宅のグローバルIP]にそれぞれアクセスして結果が返されることを確認してください。

あとはドメインDNSの設定がありますがこれらも上記サイト等に書かれているのでそちらを参考にしてください。

habomaijiro氏の歩みをマッピングするサイトを作った。

2月14日未明、毎日ラーメン二郎を食べてツイッターに感想をあげていたhabomaijiro氏による活動を中止するというツイートがありました。 何週間か前に彼が食べ歩いたラーメン屋をツイートを分析し、Google Mapに店情報、感想、画像をマッピングするサイトを公開していました。

habomai map

活動中止の理由はわかりませんが、彼がまた復帰して次郎を食べることができますように。。。