bargeOSとdockerでらくらく管理できる自宅サーバーを構築してみた

# はじめに

この記事は初心者エンジニアが自宅サーバーを構築した際のメモや構成を記したものです。
多くのWEB上の情報に助けられたので、私もこの場を借りてアウトプットしておきます。

## なぜVagrantを使ったか
y_hokkeyさんの「[Vagrant・CoreOS・Dockerでインフラ素人が自宅サーバを立てた話](https://qiita.com/y_hokkey/items/3dd0d8f20f9daadbbf0b)」を読み、マネしてみたくなったのがきっかけ。

以前はCentos7をホストOSに使い直接Nginx等をインストールする形で自宅サーバーを構築していたが、
vagrantを使うことで以前までの以下の不満点が解消された。

* Linux(centos)が使いづらい
    * 今までLinuxを触ってこなかった素人がいきなりサーバーを立てたのは無謀だったと感じた。
        * WindowsServerなら普段の環境(Windows10)とほとんど同じ感じで使えそうだった。
    * 知識がないのでネットに載っていたコマンドを直接打つしかなかった。
        * どんどん環境が散らかっていったが、整理の仕方もわからなかった。
* Dockerを使いたかった。
    * コマンド一つで環境構築したり、破棄できるのは魅力的。
* サーバーの情報のバックアップを簡単にしたかった。
    * 今まではどのファイルをバックアップすれば良いかもわからなかった。
    * 別環境にサーバーを引っ越す際にも楽ができるようになった。

# 構築した環境

* WidonwsServer 2016
    * Vagrant + VirtualBox
        * BargeOS
            * Docker v18.09.3
            * Docker-compose 1.23.2

## Dockerで動いているコンテナ
* [nginx-proxy](https://github.com/jwilder/nginx-proxy)
    * リバースプロキシ
* [docker-letsencrypt-nginx-proxy-companion](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion)
    * HTTPSに必要な証明書の取得+自動更新
* [Gitbucket](https://github.com/gitbucket/gitbucket-docker)
    * GitHubのようなGitサーバーを自前で建てられる
* [nextcloud](https://github.com/nextcloud/docker)
    * DropBoxのような環境を自前で準備できる
* [mariadb](https://hub.docker.com/_/mariadb)
    * nextcloudに必要
* [dnsmasq](https://hub.docker.com/r/andyshinn/dnsmasq)
    * LAN内にてnextcloudなどを名前解決するための内向けのDNSサーバー

# ファイル構成
```
├─barge
│  │  Vagrantfile
│  │
│  └  provision
│       always_run.sh
│       format.sh
│       mount.sh
│       startup.sh
│
├─Docker
│  │  docker-compose.yml
│  │
│  └─conf
│          server.conf
│
└─image
        data_disk.vdi
```
サーバーの設定はこのフォルダの中に全部入っているので、バックアップはこれらのフォルダのみをバックアップしておけば良い。
また、dockerの永続データはdata_disk.vdiの仮想ディスクに保存される。

## Vagrantfile
[bargeOS](https://qiita.com/A-I/items/8dc7ddc52e6038b5c74b)には公式でvagrantfileが用意されていますので、カスタマイズして使用しています。

```ruby:Vagrantfile
# A dummy plugin for Barge to set hostname and network correctly at the very first `vagrant up`
module VagrantPlugins
  module GuestLinux
    class Plugin < Vagrant.plugin("2")
      guest_capability("linux", "change_host_name") { Cap::ChangeHostName }
      guest_capability("linux", "configure_networks") { Cap::ConfigureNetworks }
    end
  end
end

$data_disk_file = "../image/data_disk.vdi"

if not File.exists?($data_disk_file) then
  $vdi_flag = false
else 
  $vdi_flag = true
end

Vagrant.configure(2) do |config|
  config.vm.define "barge", primary: true
  config.vm.box = "ailispaw/barge"
 # 実際のファイルではここには適当なIPを記載
  config.vm.network :public_network, ip: "適当なIP"
  config.vm.network "forwarded_port", guest: 80, host: 80
  config.vm.network "forwarded_port", guest: 443, host: 443
  config.vm.network "forwarded_port", guest: 53, host: 53
  config.vm.hostname = "barge"
  config.vm.synced_folder "../Docker", "/vagrant", id: "vagrant"
  config.vm.synced_folder "E:/", "/local_storage"
  # メモリを2048->4096へ変更
  config.vm.provider :virtualbox do |vb|
    vb.memory = 4096
    vm_cpus = 2
    
    # vdiファイルがない場合作成
    if $vdi_flag == false then
      vb.customize [
                      'createhd',
                      '--filename', $data_disk_file,
                      '--format', 'VDI',
                      '--size', 200 * 1024]
    end
    # vdiファイルをアタッチ
    vb.customize [
                    'storageattach', :id,
                    '--storagectl', 'SATA Controller',
                    '--port', 2,
                    '--device', 0,
                    '--type', 'hdd',
                    '--medium', $data_disk_file]
  end

  if $vdi_flag == false then
    # ファイルをフォーマットする(vdiを作成した場合)
    config.vm.provision :shell, path: "provision/format.sh"
  end
  
  if true then
    # vdiをマウントする(毎回)
    config.vm.provision :shell, path: "provision/mount.sh", run: "always"
    # startup.shの内容を実行させる(1回のみ)
    config.vm.provision :shell, path: "provision/startup.sh"
    # always_run.shの内容を実行させる(毎回)
    config.vm.provision :shell, path: "provision/always_run.sh", run: "always"
  end
end
```
```sh:provision/format.sh
(echo n; echo p; echo 1; echo ; echo ; echo w) | fdisk /dev/sdb
mkfs.ext4 /dev/sdb1
```
```sh:provision/mount.sh
mkdir -p /mnt/data_disk
mount -t ext4 /dev/sdb1 /mnt/data_disk
```
```sh:provision/startup.sh
# dockerを最新版に変更
sudo /etc/init.d/docker restart v18.09.3
 
# docker-composeのインストール
# versionを記入
ver=1.23.2
wget -L https://github.com/docker/compose/releases/download/${ver}/docker-compose-Linux-x86_64
chmod +x docker-compose-Linux-x86_64
sudo mv docker-compose-Linux-x86_64 /opt/bin/docker-compose
sudo chown root:root /opt/bin/docker-compose
docker -v
docker-compose -v
```
```sh:provision/always_run.sh
# docker-composeを起動
cd /vagrant
docker-compose up -d
```

カスタマイズした点としては、

* image/data_disk.vdi が存在しない場合に作成、フォーマットしマウントするように記載。
    * ファイルがある場合にはフォーマットはせずにマウントをおこなう。
    * Dockerの永続データに関してはこちらにすべて保存する。
        * ホストマシンに直接保存させようとするとmariadbがパーミッションの関係でエラーを吐きうまく行かなかった。
* Bargeの標準のDockerのバージョンが古いので更新し、composeのインストールも行う
    * `vagrant up`した際にはdocker-composeにてコンテナを自動で立ち上げる
* フォルダの共有は"../Docker"と"E:/"。
    * "../Docker"はdokcer-composeファイルを共有。
    * "E:/"はnextcloudで外部ストレージとして設定するため。

data_disk.vdiに関しては`vagrant destroy`を実行すると削除されてしまうので注意が必要。
ifで囲っている部分に関しては、囲まない場合プロビジョンが思い通りの順番に実行されなかったので、応急処置的に記載。

## Docker-compose
```yml:docker-compose
version: '3.5'
services:
  nginx-proxy:
    image: jwilder/nginx-proxy:0.6.0
    ports:
      - 80:80
      - 443:443
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - /mnt/data_disk/nginx/certs:/etc/nginx/certs:ro
      - /vagrant/conf/server.conf:/etc/nginx/conf.d/server.conf
      - /mnt/data_disk/nginx/vhost.d:/etc/nginx/vhost.d
      - /mnt/data_disk/nginx/html:/usr/share/nginx/html
    environment:
      - DEFAULT_HOST=ホスト名
    labels:
      - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy"
    restart: always

  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    environment:
      - NGINX_PROXY_CONTAINER=nginx-proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /mnt/data_disk/nginx/certs:/etc/nginx/certs:rw
      - /mnt/data_disk/nginx/vhost.d:/etc/nginx/vhost.d
      - /mnt/data_disk/nginx/html:/usr/share/nginx/html
    restart: always

  dnsmasq:
    restart: always
    image: andyshinn/dnsmasq
    container_name: dnsmasq
    ports:
      - "53:53/udp"
      - "53:53/tcp"
    extra_hosts:
      - "nextcloud.ホスト名:仮想マシンのIP"
      - "gitbucket.ホスト名:仮想マシンのIP"
      - "portainer.ホスト名:仮想マシンのIP"
    cap_add:
      - NET_ADMIN

  portainer:
    image: portainer/portainer
    ports:
      - 9000:9000
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /mnt/data_disk/portainer:/data
    environment:
      - VIRTUAL_HOST=portainer.ホスト名
      - VIRTUAL_PORT=9000
      - LETSENCRYPT_HOST=portainer.ホスト名
      - LETSENCRYPT_EMAIL=メールアドレス
    restart: always

  gitbucket:
    image: gitbucket/gitbucket
    volumes:
      - /mnt/data_disk/gitbucket:/gitbucket
    ports:
      - "8080:8080"
    environment:
      - VIRTUAL_HOST=gitbucket.ホスト名
      - VIRTUAL_PORT=8080
      - LETSENCRYPT_HOST=gitbucket.ホスト名
      - LETSENCRYPT_EMAIL=メールアドレス
    restart: always

  db:
    image: mariadb
    volumes:
      - /mnt/data_disk/mysql/data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=パスワード
      - MYSQL_PASSWORD=パスワード
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
    restart: always

  nextcloud:
    image: nextcloud
    ports:
      - 8090:80
    links:
      - db
    volumes:
      - /mnt/data_disk/nextcloud:/var/www/html
      - /local_storage:/local_storage
    environment:
      - VIRTUAL_HOST=nextcloud.ホスト名
      - VIRTUAL_PORT=8090
      - LETSENCRYPT_HOST=nextcloud.ホスト名
      - LETSENCRYPT_EMAIL=メールアドレス
    restart: always
```
```config:docker/server.conf
client_max_body_size 102400M;
```
今回はdockerfileは自作せず、他の方が作成したimageを使用。
ホスト名、メールアドレスなどを指定するだけであっさりとHTTPSに対応させることができた。
server.confにはnginxの転送可能な最大ファイルサイズを記載した。記載しない場合、nextcloudで1MBを超えるファイルを送れなくなる。

# 最後に

Vagrant・BargeOS・Dockerを使用することで素人でも自宅サーバーを構築することができました。
Dockerにはまだまだ面白そうなimageが多くあるので、気に入るものがあればサーバーに追加していきたいです。