2021.06.22

コーディング

環境構築

Dockerで複数サイトを運用する

個人開発でConoHaのVPSを使用して複数サイトを管理しているのですが、ConoHaのサービスにお金をチャージするのを忘れていて最初からサーバーを構築し直すハメになっちゃって色々忘れてしまってたので備忘録です。

対象

今回の記事は以下のような方を対象として書いています。

  • バーチャルホストで複数ドメインを1つのサーバーで管理しているけどもっと楽に管理したい
  • dockerを使用したことがある

個人開発していると基本的に1つのサーバーで複数サイトを管理するようになるかと思います。今回はそのやり方をdockerを使用した方法で紹介したいと思います。
また、dockerを使用したことがある方と書いてはいますが、自分もそこまでdockerに詳しくはないので細かい説明は記載してありません。
とはいえ実際に動くものを作ることでイメージが湧いてdockerについてもっと学ぶ良い機会になると思いますので分からない部分があってもまずは作ってみるというのが私のモットーです。

では早速作っていきましょう!!

開発環境

  • ConoHa VPS
  • Ubuntu 20.04.2
  • Docker version 20.10.7
  • docker-compose version 1.27.4
  • Nginx

構成


リバースプロキシ用のdocker-composeとsite-a.com用のdocker-composeとsite-b.com用のdocker-composeの3つで構成されています。

ブラウザからsite-a.com or site-b.comに80番ポートでアクセスがあるとリバースプロキシ用のコンテナがアクセスを受け取ります。
次にリバースプロキシは受け取ったホスト名によって任意のコンテナ(site-a.comかsite-b.com)へアクセスするようになってます。

最終的なファイルはこちらで公開してあります。

ネットワークの構築

docker network create --driver bridge shared

コンテナ間で通信が行えるようにネットワークを作ります。今回の場合、sharedというネットワークを作成しこれを使用しているコンテナ間で通信ができるようになります。

各コンテナの説明

リバースプロキシ用コンテナ

./shared/docker-compose.yml

version: '3'
services:

  proxy:
    image: nginx:latest
    container_name: 'proxy'
    privileged: true
    volumes:
      - ./conf.d/:/etc/nginx/conf.d
    ports:
      - "80:80"
    restart: always

networks:
  default:
    external:
      name: shared

volumesの設定でconf.dディレクトリをコンテナ内の/etc/nginx/conf.dにマウントしてリバースプロキシの設定を行っています。

portsは80番ポートを開放して受け付けれるようにしてます。

こちらでsharedネットワークに接続できるようにしています。

networks:
  default:
    external:
      name: shared

.shared/conf.d/default.conf

server {
    listen       80;

    server_name  site-a.com;

    location / {
        proxy_pass   http://site-a.com:80;
        root   /var/www/htdocs;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /var/www/htdocs;
    }
}



server {
    listen       80;

    server_name  site-b.com;

    location / {
        proxy_pass   http://site-b.com:80;
        root   /var/www/htdocs;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /var/www/htdocs;
    }
}

リバースプロキシの設定が記載されてるdefault.confの中身はserverブロックごとに各サイトの設定をしています。

site-a.com

./site-a.com/docker-compose.yml

version: '3'

services:
  site-a.com:
    image: nginx:latest
    container_name: 'site-a.com'
    volumes:
      - ./server:/var/www
      - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf
    environment:
      VIRTUAL_HOST: 'site-a.com'

networks:
  default:
    external:
      name: shared

environmentのVIRTUAL_HOSTにサイトのホスト名を記載します。
site-b.comに関しても同様の内容になるので割愛します。

コンテナを立ち上げる


docker-compose up -d #./shared
docker-compose up -d #./site-a.com
docker-compose up -d #./site-b.com

コンテナを立ち上げるとdocker network inspect sharedでsharedネットワークに繋がったことが確認できるるようになります。

Containersの中に立ち上げたコンテナが記載されているかと思います。

"Containers": {
    "b6c922c22f92fbfab18c608f66f89f5fed224216e82443a99bfc094631ef5e54": {
        "Name": "proxy",
        "EndpointID": "30c590755489ac252b86b485657df475da642d5f884e7019031f9a793d0814d0",
        "MacAddress": "02:42:ac:15:00:02",
        "IPv4Address": "172.21.0.2/16",
        "IPv6Address": ""
    },
    "d75bc433abb6508fdb9b7b8fa41e2f966cea25581b58bf3cd500db8180900136": {
        "Name": "site-b.com",
        "EndpointID": "bf77caf83b0ae0f2c648e3c3188c2a922029e6d093ec309f84264242a3124018",
        "MacAddress": "02:42:ac:15:00:04",
        "IPv4Address": "172.21.0.4/16",
        "IPv6Address": ""
     },
     "fd7c9f23e3934107854d48d8024a8f37271a9ddac8573663e02caa0450881c78": {
        "Name": "site-a.com",
        "EndpointID": "64192615ac049cf4923ebae05c981744e10ce50cd08316ef13df01cb5713a4e5",
        "MacAddress": "02:42:ac:15:00:03",
        "IPv4Address": "172.21.0.3/16",
        "IPv6Address": ""
     }
},

これで無事「site-a.com」「site-b.com」にアクセスできるようになったかと思います。
もしローカルで立ち上げている場合、hostsファイルを書き換えることで「site-a.com」「site-b.com」でアクセスができるようになっているかと思います。
/etc/hosts

127.0.0.1 site-a.com
127.0.0.1 site-b.com

リバースプロキシ用のイメージ

実は比較的簡単にリバースプロキシの設定を行えるnginx-proxyというdockerイメージがあるんですが勉強の名目も兼ねて今回は使用しませんでした。
今回自分が行った設定ではサイトが増えるごとにdefault.confに設定を追記していかないといけないのですがnginx-proxyであればネットワークが繋がってるコンテナの起動と終了を検知して
自動で設定ファイルを書き換えてくれるので楽になります。またSSL証明書を/etc/nginx/certsに置くことでHTTPSでの通信も簡単に行うことができます。

SSL化

今回、SSL化については触れてないのですが、自分の場合はConoHaのVPS内でSSL証明証を発行して証明書があるディレクトリをリバースプロキシ用のコンテナにマウントすることで解決しています。
./shared/docker-compose.yml

version: '3'
services:
  #本番用のコンテナ
  proxy_prod:
    image: nginx:latest
    container_name: 'proxy'
    volumes:
      - ./conf.d/:/etc/nginx/conf.d
      - /etc/letsencrypt:/etc/letsencrypt     #SSL証明書をマウント
    ports:
      - "80:80"
      - "443:443"
    restart: always

  #ローカル用のコンテナ
  proxy_dev:
    image: nginx:latest
    container_name: 'proxy'
    volumes:
      - ./conf.d/:/etc/nginx/conf.d
    ports:
      - "80:80"
    restart: always

networks:
  default:
    external:
      name: shared

しかしこれだとローカル開発するときに証明書がなくて困るので、本番用とローカル用で立ち上げるコンテナを変えて開発できるようにしてるんですが、
ローカルのSSL化でスマートなやり方がないか考えてる段階でかれこれ数ヶ月が立ちます・・・(笑) そろそろやらないと!!!

nginx-proxyを使用すれば比較的簡単に実装できるんですけどね・・・

課題

今回の実装の仕方だと開発するときに毎回リバースプロキシ用のコンテナを立ち上げるという手間が発生するので結構めんどくさいです。
理想はコマンド1発で開発環境が立ち上がってローカルのPC内も汚さないというのが理想なんですがまだまだ道のりは長そうです。

また今回この記事を書いていてまだまだDockerやLinuxについて理解できていない部分が多くあることを認識できたのでしっかりと1から学び直さないといけないなと感じました。

以上!!また次の機会に!!

この記事を書いた人

まだつぼみ

フロントエンドエンジニア

難しい案件やってるときが一番生きていると感じます