3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【いまさら】Docker Compose で Redmine しよう with Let's Encrypt

Last updated at Posted at 2021-01-19

やりたいこと

  • Redmine を使って個人のタスク管理 (勉強、家事、趣味) などをしたい
  • お金はかけたくない、イニシャルコストは 10K 程度、ランニングは月々数百円 くらいが良い

やろうと思ったこと

wrike も考えた

無料プランではタイムトラック機能が使えないらしい。
何に時間を使ってるかも管理したいので、残念。

planio を使おうと思った

無料プランではタグを使うためのプラグインを入れられない。有料プランは個人で使うには高すぎる。

クラウドにホストしようかと思った

bitnami を使ってさくっとクラウドにホストしようかととも考えたが、ランニングコストがアホほどかかる。
bitnami の必須構成で組んでも月々数千円かかる。

やることになったこと

自宅サーバを立てる

今どきではない感が半端ないが、クラウド() が自分のユースケースにはあっていないため、仕方がなく自分で運用保守することにした。
筐体は少電力省スペースの Raspberry Pi 4 4GB を購入した。どういうケースにしようとか SD カードどうしようとか考えるのが面倒なので、日本の販売代理店のスターターキットを買うことにした。

数年前に買ったラズパイ3はメモリ 1GB だったのに、やっぱりムーアの法則ってあるんだなぁ...。

Docker Compose を使う

今どきならk8s とかでしょ!と思うんですが、全然、勉強をしていないので、Web に投稿されている手順や設定ファイルを読み解くことができず...。なにか変えたくなった時に手も足も出なくなりそう....。

コンテナの構成は、リバースプロキシ、AP サーバ (Redmine)、DB サーバ (MariaDB) のそれっぽい構成にする。

オレオレ自己証明書を卒業する

いつの間にやら個人でも気軽に無料で(!) SSL 証明書を取得できるような世の中になっていた。Let’s Encrypt という認証局である。実際には Certbot という ACME クライアントを使用することになる。

やったこと

ネットワークの事前設定

  • DDNS へのドメインの登録
  • ルータのポートフォワーディングの設定

OS インストールから Docker Compose のインストールまで

基本的に他の Qiita の記事の通りの実施で問題ないです。
地味にネットワークの設定ファイルの変更が初回起動の際に反映されておらず、netplan の設定ファイルの保存先を探したり、自分で netplan のコマンドを実行したりした。なんだよ netplan って。

Redmine を動かす (やっと本題)

設定のパクリ元

ディレクトリ構成

ディレクトリ、ファイルの配置は以下の通り。

./
├── docker-compose.yml
├── redmine
│   ├── config.ru
│   ├── plugins
│   └── themes
└── reverse_proxy
    ├── Dockerfile
    ├── default.conf.template
    └── ssl

Redmine の設定をする

docker-compose.yml の内、AP サーバ (Redmine) の部分は以下の通り。


x-DEFINE: &APP_RELATIVE_URL_ROO
  /redmine

x-DEFINE: &DB_PASSWORD
  redmine_passward

x-DEFINE: &TIME_ZONE
  Asia/Tokyo

(略)

  app:
    image: redmine:latest
    container_name: app
    ports:
      - 3000:3000
    volumes:
      - ./redmine/plugins:/usr/src/redmine/plugins
      - ./redmine/themes:/usr/src/redmine/public/themes
      - ./redmine/config.ru:/usr/src/redmine/config.ru
    environment:
      TZ: *TIME_ZONE
      REDMINE_DB_MYSQL: db
      REDMINE_DB_PASSWORD: *DB_PASSWORD
      RAILS_RELATIVE_URL_ROOT: *APP_RELATIVE_URL_ROO
    depends_on:
      - db
    restart: always

プラグインやテーマは必要に応じてボリュームでマッピングしているディレクトリに格納するようにする。
config.ru はサブディレクトリ運用する (例えば https://my.home.com/redmine でアクセスする) ために変更が必要な設定ファイルです。変更後内容は以下の通り。RAILS_RELATIVE_URL_ROOT の値は docker-compose.yml で定義している。


# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment',  __FILE__)
map ENV['RAILS_RELATIVE_URL_ROOT'] || '/' do
    run Rails.application
end

MariaDB の設定をする

docker-compose.yml の 内、DB サーバ (MariaDB) の部分は以下の通り。特筆すべき点は特にない。

x-DEFINE: &DB_PASSWORD
  redmine_passward

x-DEFINE: &TIME_ZONE
  Asia/Tokyo

(略)
  db:
    image: mariadb:latest
    container_name: db
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD: *DB_PASSWORD
      MYSQL_DATABASE: redmine
      TZ: *TIME_ZONE
    volumes:
      - ./data/db:/var/lib/mysql
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    restart: always

nginx + certbot の設定をする

リバースプロキシ (nginx) と ssl 証明書の取得 (certbot) の設定を行う。

docker-compose.yml の リバースプロキシの部分は以下の通り。


x-DEFINE: &APP_RELATIVE_URL_ROO
  /redmine

(略)

  reverse_proxy:
    container_name: reverse_proxy
    build:
      context: ./reverse_proxy
      network: host
      args:
        - CERTBOT_EMAIL=xxxxx@yyyyy.zzzzz #replace with your own email
        - DOMAIN_LIST=my.home.com                #replace with your own domains
    environment:
      APP_ROOT: *APP_RELATIVE_URL_ROO
    volumes:
      - ./reverse_proxy/default.conf.template:/etc/nginx/templates/default.conf.template
    ports:
      - "80:80"
      - "443:443"
    restart: always

リバースプロキシのイメージは nginx の公式イメージではなく、自分でカスタムしたものをビルドする。
イメージビルド時に渡す二つのパラメータ CERTBOT_EMAIL DOMAIN_LIST は Let's Encrypt に登録する連絡用メールアドレスと ssl 証明書を取得する対象のドメイン名である。

environments で指定しているのは Redmine が動くサブディレクトリ名である。
volumes で指定しているのは nginx の設定ファイルと、ssl 認証の格納先である。

リバースプロキシの Dockerfile の内容は以下の通りである。


FROM nginx:latest
ARG CERTBOT_EMAIL=default@default.com
ARG DOMAIN_LIST

# Expose ports.
EXPOSE 80
EXPOSE 443

RUN  apt-get update \
      && apt-get upgrade -y \
      && apt-get install -y cron certbot \
      && certbot certonly --dry-run --standalone --agree-tos -m "${CERTBOT_EMAIL}" -n -d ${DOMAIN_LIST} \
     && certbot certonly  --standalone --agree-tos -m "${CERTBOT_EMAIL}" -n -d ${DOMAIN_LIST} \
      && rm -rf /var/lib/apt/lists/* \
      && echo "@monthly /usr/bin/certbot renew --nginx >> /var/log/cron.log 2>&1" >/etc/cron.d/certbot-renew \
      && crontab /etc/cron.d/certbot-renew 
VOLUME /etc/letsencrypt

CMD [ "sh", "-c", "cron && ./docker-entrypoint.sh nginx -g 'daemon off;'" ]

細かな説明はパクリ元を参照願う。
パクリ元から変更しているのは、

  • certbot のインストールを apt で行うようにした。その影響でcertbot-auto ではなくなっている。
  • entorypoint.sh から 20-envsubst-on-templates.sh が呼ばれるように CMDを変更 (ダサいとは思っているが他に思いつかない)

default.conf.template の内容は以下の通りである。
(https の設定は certbot の成功を一度確認してからコメントを外す)


server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location ${APP_ROOT} {
        proxy_set_header X-Forwarded-Host $host:$server_port;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://app:3000${APP_ROOT}/;
    }

    # --- For CertBot ---
    location ^~ /.well-known/acme-challenge/ {
        root /usr/share/nginx/html/;
    }

    location = /.well-known/acme-challenge/ {
        return 404;
    }
    # -----------------

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

#server {
#   listen 443;
#   server_name shop.nureteni.awa.co.jp;
#
#    ssl on;
#    ssl_certificate /etc/letsencrypt/live/${MY_DOMAIN_NAME}.cert;
#    ssl_certificate_key /etc/letsencrypt/live/${MY_DOMAIN_NAME}.cert.key;
#
#    location ${APP_ROOT} {
#
#    proxy_set_header X-Forwarded-Host $host:$server_port;
#    proxy_set_header X-Forwarded-Server $host;
#    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#    proxy_pass http://app:3000${APP_ROOT}/;
#    }
#    # --- For CertBot ---
#    location ^~ /.well-known/acme-challenge/ {
#        root /usr/share/nginx/html/;
#    }
#
#    location = /.well-known/acme-challenge/ {
#        return 404;
#    }
#}

以上で docker-compose up -d で必要なコンテナが立ち上がる。
あとは https://my.home.com/redmineで Redmine にアクセスできる。

おわりに

細かいことに詰まることが多く、スキマ時間にやっていたけれども 2 週間近くの時間を消費することになった。
マイナーなユースケースだと思うが、この地球のどこかの人のためになればと思い、この記事を投稿した。

3
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?