やりたいこと
- 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, ディレクトリ構成
- ngix と certbot を Docker でどう動かすか ※いつの間にか会員じゃないと見れなくなっている
ディレクトリ構成
ディレクトリ、ファイルの配置は以下の通り。
./
├── 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 週間近くの時間を消費することになった。
マイナーなユースケースだと思うが、この地球のどこかの人のためになればと思い、この記事を投稿した。