Help us understand the problem. What is going on with this article?

Phoenixで作ったアプリをNginxを前においた構成でサーバーにデプロイしたらChannelの機能が動かなかったことを解決した話[Elixir]

はじめに

  • Programming Phoenix >= 1.4 という本がありまして、英語をよちよち読みながら一周しました
  • ところどころまだまだ理解できていないところがありまして、もう一周してみることにしました
  • この本は、コード例は省略がないので、二周目は説明のところはあまり読まないことにして、コードのところだけみて写してみることにしました
  • ちょっとした機能追加もしてみました
  • できあがったものをサーバーにデプロイしてみました
  • 限定公開的な感じでアクセス元のIPは絞っています
  • 本の通りにやると、Channelsを利用したチャット機能がつくれます
  • ところがこのチャット機能が、ローカルでは動いていたはずなのに、デプロイした実行環境下では、うんともすんともいいませんでした
  • こんな感じのエラーがブラウザのJavaScriptコンソールにでていました
WebSocket connection to to wss://hogehoge.com/socket/websocket?token=<token>&vsn=2.0.0' failed: Error during WebSocket handshake: Unexpected response code: 400

結論

詳細

  • 以下、もう少し詳しくかいておきます
  • それぞれ専門にかかれている良記事があるとおもいますが、ざっと流れを記録しておきます

構成

  • EC2を使いました
    • Ubuntu 18.04.3 LTS
    • PostgreSQL 10.12
    • nginx 1.14.0
    • node v12.16.1
    • Erlang 22.1.4
    • Elixir 1.9.4-otp-22
  • セキュリティグループを使ってアクセス元のIPを限定しました
  • Let's Encryptを使って証明書を取得して、httpsにします
    • アクセス元IPを絞っているので、DNS認証で取得します

1. UbuntuがインストールされたEC2をつくる

  • 省略

2. 限られたIPからのインバウンドを許可したセキュリティグループをつくってEC2に関連づける

  • 省略

3. Ubuntuにいろいろインストールする

% ssh -i ~/.ssh/secret.pem ubuntu@<サーバーのIP>

3-1. PostgreSQL

> sudo apt update
> sudo apt install postgresql postgresql-contrib
> sudo -u postgres psql postgres
\password postgres

3-2. node

3-3. Erlang と Elixir

  • asdf-vmを使ってインストールします
> git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.7.7
> echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.bashrc
> echo -e '\n. $HOME/.asdf/completions/asdf.bash' >> ~/.bashrc
> source ~/.bashrc
> sudo apt install \
  automake autoconf libreadline-dev \
  libncurses-dev libssl-dev libyaml-dev \
  libxslt-dev libffi-dev libtool unixodbc-dev \
  unzip curl
> asdf plugin add erlang
> asdf plugin add elixir
> asdf install erlang 22.1.4
> asdf global erlang 22.1.4
> asdf install elixir 1.9.4-otp-22
> asdf global elixir 1.9.4-otp-22

3-4. Let's Encrypt を使って証明書を取得する

> apt -y install certbot
> sudo certbot certonly --server https://acme-v02.api.letsencrypt.org/directory --manual --preferred-challenges dns -d hogehoge.com --email torifukukaiou@hogehoge.com
/etc/nginx/conf.d/hogehoge.conf
server {
  listen 80;
  server_name hogehoge.com;
  return 301 https://$host$request_uri;
}

server {
  listen       443 ssl http2 default_server;
  listen       [::]:443 ssl http2 default_server;
  server_name  hogehoge.com;
  root         /usr/share/nginx/html;

  ssl_certificate "/etc/letsencrypt/live/hogehoge.com/fullchain.pem";
  ssl_certificate_key "/etc/letsencrypt/live/hogehoge.com/privkey.pem";
  # It is *strongly* recommended to generate unique DH parameters
  # Generate them with: openssl dhparam -out /etc/pki/nginx/dhparams.pem 2048
  # ssl_dhparam "/etc/pki/nginx/dhparams.pem";
  ssl_session_cache shared:SSL:1m;
  ssl_session_timeout  10m;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP;
  ssl_prefer_server_ciphers on;

  location / {
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_redirect off;
    proxy_set_header X-Real-IP $remote_addr;

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_http_version 1.1;
    proxy_pass http://127.0.0.1:4000;
  }
}
> sudo nginx -t
> sudo nginx -s reload

4. Phoenixを動かす

$ mix phx.gen.secret
REALLY_LONG_SECRET
~/.bashrc
export SECRET_KEY_BASE="REALLY_LONG_SECRET"
export DATABASE_URL="ecto://postgres:postgres@localhost:5432/hello_prod"
  • ↑こういうのを書き足します
  • 公式に書いてある ecto://USER:PASS@HOST/database => これを上のように書き換えるわけですが、いわれてみれば確かになるほど! なのですが悩みました
    • ectoのところをこれもあくまでも例で、MySQLだとかわったりするのだろうと変に考えてpostgresqlにしたりして余計な変更をしていたせいです:baby_tone2:
  • いつものようにpiacere_exさんの記事に助けてもらいました
config/prod.exs
config :hello, HelloWeb.Endpoint,
  url: [host: "hogehoge.com", port: 443],
  cache_static_manifest: "priv/static/cache_manifest.json"
$ source ~/.bashrc 
$ mix deps.get --only prod
$ MIX_ENV=prod mix compile
$ MIX_ENV=prod mix ecto.create
$ MIX_ENV=prod mix ecto.migrate
$ npm run deploy --prefix ./assets
$ mix phx.digest
$ MIX_ENV=prod nohup mix phx.server &
  • /etc/nginx/conf.d/hogehoge.conf の設定が足りなくてチャット機能が動かなかったわけですが、私の実感としては、ローカルだと動いていたはずなのにー と、最後の最後のほうで右往左往していました

  • いろいろありましたが、無事動いてよかったです :rocket:

    • 時間にすると、4のところが一番時間はかかっていないのですが、なぜ動かないんだーと途方にくれていたので一番時間を使ったような気分になりました
fukuokaex
エンジニア/企業向けにElixirプロダクト開発・SI案件開発を支援する福岡のコミュニティ
https://fukuokaex.fun/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away