※Github
小改良して再利用しやすくしました
たぶんReadmeどおりにやればいけるはず
WindowsのDocker Desktopはファイル権限絡みでバグりやすいので、Linux奨励です
きっかけ
これまで写真はAmazon photos、ファイルはGoogleDrive 100GBに保存してきたが、Amazon Drive廃止、Google Photos無制限廃止などあって不安になってきた。
Amazon photosもアルバムにして整理している分以外の写真の一括ダウンロードが難しいので仕様変更あると困るなと思い、自宅にもデータを置いておきたくなった。
あとはよくわからない理由で垢バンされて過去の写真全部パアとかになった例を聞くので。
方針
- 移植のしやすさ、安定性、セキュリティ等々考えてDockerで構築
- 証明書はLet's encrypt
- DDNSはMyDNS
- DNS通知とか証明書更新の定期実行も一包化したい
- 管理しやすくするために変数は変数ファイルに格納してスクリプトと分けておく
やる
nextcloudイメージのgithubにdocker-composeで構築するサンプルがあるのでこれを参考に作る。
構成
最初に構成を載せておきます。
nextcloud_docker
│ .env
│ db.env
│ docker-compose.yml
│ Readme.txt
│
├─mydns_letsencrypt
│ │ Dockerfile
│ │ letsencrypt-cert.sh
│ │ txtedit.conf
│ │
│ ├─crontabs
│ │ root
│ │
│ └─mydns
│ mydns-notify.sh
│ mydns.env
│
└─proxy
└─conf.d
uploadsize.conf
変数ファイル
.envはdocker-compose.yml内の変数を指定します。
letsencrypt-cert.shでもこれを読み込んでいます。
MAILADDR=<メールアドレス>
DOMAIN=<ドメイン>
CERT_NAME=nextcloud
DATA_DIR=<Nextcloudデータの格納場所>
MariaDBのパラメータです。
MYSQL_PASSWORD=<MySQLのパスワード>
MYSQL_ROOT_PASSWORD=<MySQLのルートパスワード>
MYSQL_DATABASE=nextcloud
MYSQL_USER=nextcloud
MyDNSのログイン情報
MYDNSID='<MyDNSのID>'
MYDNSPW='<MyDNSのパスワード>'
ポート開放
使いたいポートを開放しておいてください。今回はルータではポート変換しない設定で行きます。
MyDNSでのドメイン取得
MyDNSでのドメイン取得方法は多くの記事があるのでそちらに譲ります。
Let's encryptでの証明書取得
サンプル内で使われているnginxproxy/acme-companionイメージはHTTP-01チャレンジのみ対応のため、80, 443ポートを開かないと使えない。我が家はOCNバーチャルコネクトのため、開けるポートが制限されており、80も443も開けません。
そこでMyDNSJPの方が用意してくれているDNS-01チャレンジ用のスクリプトをDockerイメージにして使います。
加えて初回取得は手動で行い、その後の更新は定期実行とするため、busyboxを使えるようにしておきます。
FROM debian:stable
WORKDIR /DirectEdit/
RUN apt-get -y update && \
apt-get -y install busybox-static wget unzip certbot php php7.4-mbstring && \
apt-get -y autoremove && apt-get -y clean
RUN wget 'https://github.com/disco-v8/DirectEdit/archive/master.zip' -O DirectEdit-master.zip && unzip ./DirectEdit-master.zip
WORKDIR /DirectEdit/DirectEdit-master
RUN chmod 700 ./*.php && chmod 600 ./*.conf
COPY txtedit.conf .
CMD busybox crond -f
このイメージを下記のコードでビルドしてcertbotを走らせてやると証明書が取得できる。
source $(cd $(dirname $0); pwd)/../.env
docker build -t certbot $(cd $(dirname $0); pwd)
docker run -it --rm \
--name certbot \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /var/lib/letsencrypt:/var/lib/letsencrypt \
certbot \
certbot certonly --manual --keep\
--preferred-challenges=dns \
--manual-auth-hook /DirectEdit/DirectEdit-master/txtregist.php \
--manual-cleanup-hook /DirectEdit/DirectEdit-master/txtdelete.php \
-d ${DOMAIN} -d *.${DOMAIN} \
--server https://acme-v02.api.letsencrypt.org/directory \
--agree-tos -m ${MAILADDR} \
--manual-public-ip-logging-ok
# nginxから認識できるように鍵と証明書の名前を変更しておく
cp /etc/letsencrypt/live/${DOMAIN}/cert.pem /etc/letsencrypt/live/${DOMAIN}/${CERT_NAME}.crt
cp /etc/letsencrypt/live/${DOMAIN}/privkey.pem /etc/letsencrypt/live/${DOMAIN}/${CERT_NAME}.key
DDNS通知と証明書更新の定期実行
MyDNSはDDNSのため、定期的に通知を行ってあげないと無効化します。また、証明書は期限付きのため、定期的に更新する必要があります。定期実行はbusybox crondで行います。今回は証明書更新は週1回、DDNS通知は毎日行うことにしました。
使うイメージは証明書取得に使ったのと同じものです。ここで引っかかったのが、crontabs/rootの所有者をrootにしておかないとジョブが実行されないこと。
sudo chown root:root root
で変更しておきます。
0 0 * * 0 certbot renew
0 0 * * * bash /mydns/mydns-notify.sh
DDNS通知
source $(cd $(dirname $0); pwd)/mydns.env
wget -O - http://${MYDNSID}:${MYDNSPW}@www.mydns.jp/login.html
docker-composeにまとめる
proxyコンテナに入るところでポートを変換しています。
version: '3'
services:
proxy:
image: nginxproxy/nginx-proxy:alpine
restart: always
ports:
- 1750:80
- 1751:443
volumes:
- /etc/letsencrypt/live/${DOMAIN}:/etc/nginx/certs:ro
- ./proxy/conf.d:/etc/nginx/conf.d
- vhost.d:/etc/nginx/vhost.d
- html:/usr/share/nginx/html
- /var/run/docker.sock:/tmp/docker.sock:ro
environment:
- TZ=Asia/Tokyo
networks:
- proxy-tier
db:
image: mariadb:10.5
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
restart: always
volumes:
- db:/var/lib/mysql
env_file:
- db.env
redis:
image: redis:alpine
restart: always
app:
image: nextcloud:apache
restart: always
volumes:
- ${DATA_DIR}:/var/www/html
environment:
- NEXTCLOUD_TRUSTED_DOMAINS=${DOMAIN}
- VIRTUAL_HOST=${DOMAIN}
- OVERWRITEPROTOCOL=https
- CERT_NAME=${CERT_NAME}
- MYSQL_HOST=db
- REDIS_HOST=redis
env_file:
- db.env
depends_on:
- db
- redis
networks:
- proxy-tier
- default
cron:
image: nextcloud:apache
restart: always
volumes:
- ${DATA_DIR}:/var/www/html
entrypoint: /cron.sh
depends_on:
- db
- redis
mydns_letsencrypt:
build: ./mydns_letsencrypt
restart: always
tty: true
volumes:
- ./mydns_letsencrypt/crontabs:/var/spool/cron/crontabs
- ./mydns_letsencrypt/mydns:/mydns
- /etc/letsencrypt:/etc/letsencrypt
- /var/lib/letsencrypt:/var/lib/letsencrypt
environment:
- TZ=Asia/Tokyo
volumes:
db:
nextcloud:
vhost.d:
html:
networks:
proxy-tier:
起動
これでdocker-compose up -d
してあげれば、Nextcloudを起動できるかと思います。
信頼できるドメインの追加
これで接続できるのだが、信頼されていないドメインというエラーが出る。
nextcloudのdockerイメージにNEXTCLOUD_TRUSTED_DOMAINSという変数があり、そこに自分のドメインを示しておけば行けるはずなのだが、どうもバグで機能しない例が多いみたいなので
sudo docker-compose exec --user www-data app php occ config:system:set trusted_domains 2 --value=<ドメイン>
を実行して追加してあげましょう。