以前買ったミニ PC を自宅サーバーにしようとしていたのだが、まったく時間が無くて放置していた。育休中に少し時間が取れたので、とりあえず Ubuntu をインストールして Nextcloud を動かしてみた。docker を使って構成したが結構ハマったので、その辺のメモ。
ネットワーク構成について
IIJMio ひかりを使っているので、普段は DS-Lite IPv4 over IPv6 での通信をしている。ネットワークは詳しくないが、DS-Lite では複数のユーザーが同一の IPv4 アドレスを共有することになるので、ポートフォワードができない。
当初は IPv4 での外部アクセスと DS-Lite の両立を目指したが実際に PPPoE 接続を試したところ、日中や夕方の混雑隊でも DS-Lite と遜色がないことが分かった。ということで、PPPoE で普通にルーターで NAT する。
ネットワークが遅いと感じたらその時に勉強します。一般のご家庭なので…。
速度測定は speedtest-cli で行った。
sudo apt-get install curl
curl -s https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh | sudo bash
sudo apt-get install speedtest
cron で定期的に測定するようにしたのだが、sppedtest コマンドだけでは日付が出ないので、3日ぐらい無駄にした。あらかじめ適当にヘッダーを追加しておくこと。
24 * * * * now=\"$(date +"\%Y-\%m-\%d \%H:\%M:\%S")\",; /usr/bin/speedtest -f csv -s 48463 | sed "s/^/$now/" >> /home/user/speedtest.csv
jupyter notebook で pandas で読み込んでグラフ化。こういうのは Copilot Chat に聞けば勝手にやってくれるので嬉しい。
import pandas as pd
import matplotlib.pyplot as plt
# Load the CSV file
data = pd.read_csv('speedtest.csv')
data['download Mbps'] = data['download'] / 125000
data['upload Mbps'] = data['upload'] / 125000
# Assuming 'time' is the column with time information
data['time jst'] = pd.to_datetime(data['datetime utc']).dt.tz_localize('UTC').dt.tz_convert('Asia/Tokyo')
# Extract hour from time
data['hour'] = data['time jst'].dt.hour
# Set 'time jst' as the index of the DataFrame
data.set_index('time jst', inplace=True)
# Plot 'download Mbps' and 'upload Mbps' over time
data[['download Mbps', 'upload Mbps']].plot()
# Show the plot
plt.show()
# Group by hour and calculate mean download speed
average_speed_by_hour = data.groupby('hour')['download Mbps'].mean()
# Plot the average download speed by hour
average_speed_by_hour.plot()
plt.show()
遅いときでも上下 500Mbps ぐらい出ているので、特に問題はなさそうだ。
Ubuntu 22.04 のセットアップでインストールされる Docker が古い
Ubuntu 22.04 の初期セットアップ中に色々とパッケージのインストールができるのだが、パッケージマネージャーに snap が採用されている。snap で Docker をインストールすると、最新バージョンではない古いバージョンがインストールされてしまう。
あまり問題になることはないと思うが、私の環境では以下のバグを踏んでしまい docker compose exec が使えなくなってしまった。
[BUG] docker-compose http: invalid Host header · Issue #11154 · docker/compose
sudo snap refresh docker --channel=latest/edge
でバージョンを更新できるらしいが、その情報を見つける前に snap の docker をアンインストールして、公式のインストール手順を参考にインストールし直してしまった。
sudo aa-remove-unknown
snap list
sudo snap remove docker
# 再起動後 Docker 公式のインストール手順を実施
Nextcloud を Docker で動かす
ググれば色々記事があるが、Nextcloud All-in-One (Nextcloud AIO) を利用するか snap でホストに直接インストールするのが一番楽そうだった。特に AIO 版は機能モリモリで便利なのだが、AIO 自体が docker コンテナを複数立ち上げるようなオーケストレーションツールのような感じで、重厚過ぎるので今回はパス。
そもそも、フロントに nginx-proxy を置いて検証アプリを色々動かしたかったため、自分で docker-compose.yml を書くことにした。
ngix-proxy
nginx-proxy は docker.sock をマウントして、起動中のコンテナを監視して自動でリバースプロキシの設定を行ってくれる。nginxproxy/acme-companion は nginx-proxy が設定したリバースプロキシの設定を元に Let’s Encrypt の証明書を自動で取得してくれる
あらかじめ docker network create proxy-network --subnet 172.18.0.0/16
でネットワークを作成しておく。サブネットは Nextcloud の Trusted Proxy のために定義する。
version: '3'
services:
nginx-proxy:
image: nginxproxy/nginx-proxy
container_name: nginx-proxy
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./certs:/etc/nginx/certs:rw
- ./vhost.d:/etc/nginx/vhost.d
- ./html:/usr/share/nginx/html
- ./custom-nginx.conf:/etc/nginx/conf.d/custom-nginx.conf:ro
networks:
proxy-network:
ipv4_address: 172.18.0.2
labels:
- com.github.nginx-proxy.nginx-proxy.keepalive=auto
letsencrypt:
image: nginxproxy/acme-companion
container_name: nginx-acme
depends_on:
- nginx-proxy
environment:
- DEFAULT_EMAIL=${MAILADDRESS}
- NGINX_PROXY_CONTAINER=nginx-proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./certs:/etc/nginx/certs:rw
- ./vhost.d:/etc/nginx/vhost.d
- ./html:/usr/share/nginx/html
networks:
- proxy-network
ddclient:
image: lscr.io/linuxserver/ddclient:latest
container_name: ddclient
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- ./ddclient_conf:/config
restart: unless-stopped
networks:
proxy-network:
external: true
driver: bridge
ipam:
config:
- subnet: 172.18.0.0/16
ウチの IP は動的アドレスなので、ddclient で DNS を更新する。CloudFlare の場合はこんな感じ。CloudFlare の API トークンは DNS Read, Write の権限で十分だった。
なお、あらかじめ DNS レコードがないと動作しないので、手動で作成しておくこと。
# Even though we use -foreground, daemon= is still needed.
# It's value here is ignored, but it's needed. The value used is set in
# ddclient.in in the dockerfile.
daemon=0
verbose=no
ssl=yes
use=web, web=he # checkip.dns.he.net
protocol=cloudflare
login=token
password='yourtoken'
zone=example.com
dns1.example.com, dns2.example.com
/etc/nginx/vhost.d
にホスト名のファイルを置くことで、各ホストごとに追加設定ができる。例えば example.com 向けの設定を追加したければ /etc/nginx/vhost.d/example.com
のファイルを追加する。Nextcloud のホスト名でタイムアウトや Body 上限の変更などをしておく。
send_timeout 300;
keepalive_timeout 300;
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_send_timeout 300;
client_max_body_size 1G;
Nextcloud 本体
ngix-proxy を使っていて nginx 側はいじりたくなかったので、apache 版を 公式のサンプル をもとに作成した。
nginx-proxy の vhost.d/ に頑張って設定ファイルを書けば nextcloud:fpm 版を良い感じに使えそうだったけど、php にも nginx の設定も詳しくないので、とりあえず apache 版で。
出来上がったのがこれ。
version: '3'
services:
nextcloud:
build: ./customimages/nextcloud
container_name: nextcloud
volumes:
- nextcloud_data:/var/www/html
# - ./config:/var/www/html/config # for debug
- ./log/:/var/log/nextcloud/
- ./skeleton/:/var/skeleton/
- /mnt/hdd01/:/mnt/hdd01/
env_file:
- ./.env
- ./env/db.env
- ./env/nextcloud.env
secrets:
- nextcloud_admin_password
- nextcloud_admin_user
- mysql_password
- mysql_user
- mysql_database
- smtp_password
networks:
- proxy-network
- nextcloud-network
depends_on:
- db
- redis
- elasticsearch
nextcloud-cron:
build: ./customimages/nextcloud
container_name: nextcloud-cron
restart: unless-stopped
env_file:
- ./.env
- ./env/db.env
- ./env/nextcloud.env
volumes:
- nextcloud_data:/var/www/html
# - ./config:/var/www/html/config # for debug
- ./log/:/var/log/nextcloud/
- ./skeleton/:/var/skeleton/
- /mnt/hdd01/:/mnt/hdd01/
# if customize cron file
# https://help.nextcloud.com/t/docker-setup-cron/78547/5
# https://github.com/nextcloud/docker/blob/ccdf46609ff8419ffd7c5ce4e51a117e378b72b6/Dockerfile-debian.template#L15
# - ./mycronfile:/var/spool/cron/crontabs/www-data
secrets:
- nextcloud_admin_password
- nextcloud_admin_user
- mysql_password
- mysql_user
- mysql_database
- smtp_password
networks:
- nextcloud-network
entrypoint: /cron.sh
depends_on:
- nextcloud
db:
image: mariadb
container_name: nextcloud-db
volumes:
- db_data:/var/lib/mysql
env_file:
- ./.env
- ./env/db.env
secrets:
- mysql_database
- mysql_password
- mysql_user
- mysql_root_password
networks:
- nextcloud-network
redis:
image: redis:6
container_name: nextcloud_redis
restart: always
command: ["--databases", "1"]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
volumes:
- redis_data:/data
networks:
- nextcloud-network
elasticsearch:
build: ./customimages/elasticsearch
container_name: elasticsearch
restart: always
environment:
- discovery.type=single-node
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- xpack.security.enabled=false
volumes:
- elasticsearch_data:/usr/share/elasticsearch/data
networks:
- nextcloud-network
secrets:
nextcloud_admin_password:
file: ./secrets/nextcloud_admin_password
nextcloud_admin_user:
file: ./secrets/nextcloud_admin_user
mysql_password:
file: ./secrets/mysql_password
mysql_user:
file: ./secrets/mysql_user
mysql_database:
file: ./secrets/mysql_database
mysql_root_password:
file: ./secrets/mysql_root_password
smtp_password:
file: ./secrets/smtp_password
volumes:
nextcloud_data:
db_data:
redis_data:
elasticsearch_data:
networks:
proxy-network:
external: true
driver: bridge
ipam:
config:
- subnet: 172.18.0.0/16
nextcloud-network:
driver: bridge
ポイントメモ
Nextcloud 本体は nginx-proxy と同一のネットワークにおいて、それ以外のコンテナ nextcloud-network を作成してそこに配置した。
環境変数
.env ファイルなどの中身はこんな感じ。
#for nginx-proxy
VIRTUAL_HOST=${YOUR_DOMAIN}
LETSENCRYPT_HOST=${YOUR_DOMAIN}
LETSENCRYPT_EMAIL=${MAIL_ADDRESS}
# trust nginx proxy
TRUSTED_PROXIES=172.18.0.2/32
OVERWRITEHOST=${YOUR_DOMAIN}
OVERWRITEPROTOCOL=https
#admin password
NEXTCLOUD_ADMIN_PASSWORD_FILE=/run/secrets/nextcloud_admin_password
NEXTCLOUD_ADMIN_USER_FILE=/run/secrets/nextcloud_admin_user
NEXTCLOUD_TRUSTED_DOMAINS=${YOUR_DOMAIN}
# redis settings
REDIS_HOST=nextcloud_redis
# smtp settings
SMTP_HOST=smtp.sendgrid.net
SMTP_NAME=apikey
SMTP_PASSWORD_FILE=/run/secrets/smtp_password
MAIL_FROM_ADDRESS=noreply
SMTP_SECURE=tls
SMTP_AUTHTYPE=LOGIN
MAIL_DOMAIN=${MAIL_DOMAIN}
# other settings
PHP_UPLOAD_LIMIT=10G
NC_default_phone_region=JP
NC_logtype=file
NC_logfile=/var/log/nextcloud/nextcloud.log
NC_loglevel=0
NC_default_language=ja
NC_default_locale=ja_JP
NC_default_timezone=Asia/Tokyo
NC_skeletondirectory=/var/skeleton/
NC_maintenance_window_start=16
NC_ プレフィックスがつく環境変数は config.php の設定を上書きする。環境変数含め config.php に直接書き込むのではなく、値を無視して環境変数が上書きされるので注意。なので設定が間違っていた場合、コンテナ内の confing.php を直接書き換えても反映されない。これにハマって 2, 3 時間無駄にした。上記設定をすれば最低限管理画面で警告が出なくなるはず。
ちなみに、Nextcloud の環境変数は変数名の末尾に _FILE とつけることで、docker の secrets で管理できる。Nextcloud や拡張機能のの脆弱性などで環境変数が漏れた時に備えて、パスワード系は secrets で管理することにした。
SendGrid
メールの配信は SendGrid を使っている。SMTP_NAME は apikey, SMTP_PASSWORD には SendGrid の API キーを設定する。
skelton ディレクトリ
新規作成したユーザーに対してデフォルトで配置されるファイルを指定できる。既定だとサンプルの画像などが入っているので NC_skeletondirectory=/var/skeleton/ で指定して、docker-compose.yml でマウントしておく。使い方の PDF でもつくってツッコんでおく
ログ
apache 版の docker イメージは apache のログしか stdout に出力しないので docker compose logs などで Nextcloud 側のログが確認できない。またファイル出力されていなければ、Web の管理コンソールでログが見えなくて不便なのでファイルに出力するよう修正。出力先の /var/log/nextcloud/ フォルダーはカスタムイメージ内で作成して www-data にオーナーを変更しておく。 安定稼働までは NC_loglevel でログレベルを 0 (DEBUG) にしてある。しばらくしたら 3 (ERROR) に戻す。
バックアップ
バックアップは雑に docker volume を tar で固めて、外部ストレージ & Azure Blob に保存している。リストアは出来ることを確認したけど、雑は雑。
# maintenance mode on
# https://doc.owncloud.com/server/next/admin_manual/maintenance/enable_maintenance.html
cd /home/watahani/docker_apps/nextcloud
docker compose exec -u www-data nextcloud php occ maintenance:mode --on
date=`date '+%Y-%m-%d'`
VOLUMES=("nextcloud_db_data" "nextcloud_nextcloud_data" "nextcloud_redis_data" "elasticsearch_data")
for VOLUME_NAME in ${VOLUMES[@]}; do
echo back up $VOLUME_NAME start
BACKUP_DESTINATION=/mnt/exthdd/owncloud_backup/$VOLUME_NAME.tar.gz
sudo tar -czf "$BACKUP_DESTINATION" -C "/var/lib/docker/volumes/$VOLUME_NAME" _data
echo upload $VOLUME_NAME start
azcopy copy $BACKUP_DESTINATION "https://example.blob.core.windows.net/backup/$VOLUME_NAME-$date.tar.gz"
echo back up $VOLUME_NAME finish!
done
docker compose exec -u www-data nextcloud php occ maintenance:mode --off
azcopy login が廃止予定になるらしく、サービス プリンシパルでの認証の場合、あらかじめ環境変数に AZCOPY_SPA_APPLICATION_ID, AZCOPY_SPA_CLIENT_SECRET, AZCOPY_TENANT_ID, AZCOPY_AUTO_LOGIN_TYPE=SPN を設定しておくこと。
INFO: 'azcopy login' command will be deprecated starting release 10.22. Use auto-login instead. Visit https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-authorize-azure-active-directory#authorize-without-a-secret-store to know more.
インタラクティブな認証は azure-cli でログインしておいてその認証情報を使いまわす実装に移行していくようだ。
最悪アップロードした写真データが無事なら良いのでまあこれでヨシ。
カスタムアプリ
この辺を入れた
- memories
- fulltextsearch
- fulltextsearch_elasticsearch
- previewgenerator
コマンドで入れるなら docker compose exec -u www-data nextcloud php occ app:install memories
のようにする。
構築していた当時、https://apps.nextcloud.com/ が異常に重く、アプリのインストールがタイムアウトで出来なかった。
{"reqId":"CIl2uB04J5qvKBuCFJOe","level":2,"time":"2024-02-03T13:31:32+00:00","remoteAddr":"","user":"--","app":"appstoreFetcher","method":"","url":"--","message":"Could not connect to appstore: cURL error 28: Operation timed out after 60000 milliseconds with 2514944 out of 6055936 bytes received (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://apps.nextcloud.com/api/v1/apps.json","userAgent":"--","version":"28.0.2.5","data":{"app":"appstoreFetcher"}}
幸い何度か試せば通信で切るときがあったので、一時的にオリジナルの json ファイルを Blob において対処した。具体的には https://apps.nextcloud.com/api/v1/apps.json と https://apps.nextcloud.com/api/v1/categories.json をダウンロードして、適当なサイト、同じパスで公開する。
その後、config.php の appstoreurl に、https://<適当なサイト>/api/v1 を設定する。
docker compose exec -u www-data nextcloud php occ --no-warnings config:system:set appstoreurl --value="https://<適当なサイト>/api/v1"
元のサイトが復旧したら元に戻す
docker compose exec -u www-data nextcloud php occ --no-warnings config:system:delete appstoreurl
Elastic Search
Elastic Search は日本語検索のために kuromoji_tokenizer を使うように設定しておく。そのために Dockerfile についてもカスタマイズしている。
# Probably from here https://github.com/elastic/elasticsearch/blob/main/distribution/docker/src/docker/Dockerfile
FROM elasticsearch:8.12.0
USER root
# hadolint ignore=DL3008
RUN set -ex; \
\
export DEBIAN_FRONTEND=noninteractive; \
apt-get update; \
apt-get install -y --no-install-recommends \
tzdata \
; \
rm -rf /var/lib/apt/lists/*; \
elasticsearch-plugin install --batch ingest-attachment;\
elasticsearch-plugin install --batch analysis-kuromoji;\
elasticsearch-plugin install --batch analysis-icu
USER 1000:0
HEALTHCHECK CMD nc -z localhost 9200 || exit 1
LABEL com.centurylinklabs.watchtower.enable="false"
fulltextsearch を入れたら、Web の管理コンソールから http://elasticsearch:9200 と、トークナイザーに kuromoji_tokenizer を指定する。
その後、以下のコマンドでインデックスの初期作成をしておく
docker compose exec -u www-data nextcloud php occ fulltextsearch:reset
docker compose exec -u www-data nextcloud php occ fulltextsearch:index
インデックスの定期作成については、Ubuntu22.04 DockerでNextcloud | ろっひー を参考に /var/www/html/occ fulltextsearch:live –service コマンドを起動スクリプトから呼びだすよう Dockerfile をカスタマイズした。
ファイルが多く処理に時間がかかったり、バッチ処理をしたいのであれば後述の cron に fulltextsearch:index をジョブとして追加すれば良いだろう。
memories と previewgenerator
memories を入れることにより Google Photo のように日付ごとに写真を表示したり、人物や場所ごとに写真を表示したりできるようになる。画像認識は別途プラグインが必要なので、今回は試していない。
また、memories のプレビュー生成には ffmpeg が必要なので、Dockerfile に ffmpeg を追加した。
memories のドキュメントによると Nextcloud 既定では 2048px のプレビュー画像を生成するらしいので、少し小さく。
docker compose exec -u www-data nextcloud php occ config:system:set preview_max_x --value="1024"
docker compose exec -u www-data nextcloud php occ config:system:set preview_max_y --value="1024"
previewgenerator も初期作成をしておく
docker compose exec -it -u www-data nextcloud php occ config:app:set --value="64 256 1024" previewgenerator squareSizes
docker compose exec -it -u www-data nextcloud php occ config:app:set --value="64 256 1024" previewgenerator widthSizes
docker compose exec -it -u www-data nextcloud php occ config:app:set --value="64 256 1024" previewgenerator heightSizes
出来たら初回のプレビュー生成を行う
nohup docker compose exec -u www-data nextcloud php occ preview:generate-all&
終わったら以下コマンドを nextcloud-cron に追加して定期的に差分生成するよう構成する。
php /var/www/nextcloud/occ preview:pre-generate
cron
Nextcloud の cron ジョブは、nextcloud-cron として別コンテナで起動している。
既定では php -f /var/www/html/cron.php が 5 分ごとに実行される。上書きしたければ /var/spool/cron/crontabs/www-data
をマウントするなどしてカスタマイズする。
memories や previewgenerator を適当に定期実行するように設定する。この時 cron ファイルの所有者が root でなければ失敗するので注意。
docker compose cp nextcloud-cron:/var/spool/cron/crontabs/www-data ./mycronfile
echo '30 18 * * * php /var/www/html/occ preview:pre-generate' >> ./mycronfile
echo '5 * * * * php /var/www/html/occ memories:index' >> ./mycronfile
sudo chown root:root ./mycronfile
コンテナにマウント
nextcloud-cron:
build: ./customimages/nextcloud
container_name: nextcloud-cron
restart: unless-stopped
env_file:
- ./.env
- ./env/db.env
- ./env/nextcloud.env
volumes:
- nextcloud_data:/var/www/html
# - ./config:/var/www/html/config # for debug
- ./log/:/var/log/nextcloud/
- ./skeleton/:/var/skeleton/
- /mnt/hdd01/:/mnt/hdd01/
# if customize cron file
# https://help.nextcloud.com/t/docker-setup-cron/78547/5
# https://github.com/nextcloud/docker/blob/ccdf46609ff8419ffd7c5ce4e51a117e378b72b6/Dockerfile-debian.template#L15
- ./mycronfile:/var/spool/cron/crontabs/www-data
Google Taskout からの移行
今回は Google Photo からの移行なので、Google Takeout からファイルをエクスポートして、Nextcloud に取り込む。保存したパスを外部ストレージとしてマウントしても良いのだが、今後アップロードするスマホのカメラ画像と同様の扱いにしたかったので、Nextcloud に直接取り込む。
memories がメタデータを読み込んでくれるらしいので、ファイルを Nextcloud に転送後に以下を実行する。
# ファイルを直接 docker volume に転送
sudo mv ./Takeout /var/lib/docker/volumes/{volume_name}/_data/data/{username}/
# インデックスを作成
docker compose exec -u www-data nextcloud php occ files:scan --path="{username}/files/Takeout"
# Google Takeout のメタデータを読み込む
docker compose exec -u www-data nextcloud sh -c 'yes | php occ memories:migrate-google-takeout'
が、手元の環境ではうまく動かないファイルがあったので、TheLastGimbus/GooglePhotosTakeoutHelper: Script that organizes the Google Takeout archive into one big chronological folder を使ってメタデータを書き込んだ。
guess-from-name オプションはファイル名などから日付を推測してくれるらしい。実際に memories で取り込めなかったデータなどが、フォルダ名の日付を元に取り込まれたので助かった。アルバムは既定では元ファイルは日付フォルダに入れてアルバム用にシンボリックリンクを張る設定らしいので、nothing にしておく。
wget https://github.com/TheLastGimbus/GooglePhotosTakeoutHelper/releases/download/v3.4.3/gpth-linux
chmod +x gpth-linux
./gpth-linux -i ./Takeout/ -o ./output --divide-to-dates --guess-from-name --albums nothing
メタデータの変換後、念のためバックアップ後にフォルダーを直接 Docker Volume の中に移動。
sudo mv ./output/ALL_PHOTOS /var/lib/docker/volumes/{volume_name}/_data/data/{username}/
docker compose exec nextcloud chown -R www-data:www-data /var/lib/docker/volumes/{volume_name}/_data/data/{username}/Takeout
インデックス作る
docker compose exec -u www-data nextcloud php occ files:scan --path="{username}/files/Takeout"
雑だけど動いたのでヨシッ!そもそもメタデータがうまく取り込めない古いファイルは、家の HDD にオリジナルがあるのでどこかのタイミングでそれに差し替えよう。
最後に
Docker で Nextcloud を動かすメモ。フォーラムも公式ドキュメントもかなり充実しているものの、docker で動かすにはそれなりに苦労した。バージョンアップや監視についてはまだ出来ていないので、単に Nextcloud だけが目的であれば snap で入れるのが一番楽だろう。
最後に認証の話をしておくと Nextcloud 自体は Passkey に対応しているようで、個人設定から Android デバイスや Windows Hello を追加できた。
ただモバイル アプリではログイン時に Chrome などが起動するのではなく、hwsecurity.dev という会社が提供している SDK が組み込まれた独自ブラウザーが起動して、Security Key しか使えない UX になっていた。そのため 2FA を有効にしたうえでモバイルアプリを利用する場合、PC でアプリパスワードを発行するか、セキュリティ キーや OTP など別の認証要素を登録しておく必要があるので注意。