2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Nextcloud + Tailscale + Raspberry Piで家族写真クラウド兼フォトフレームを作る

2
Last updated at Posted at 2026-05-01

この記事について

Windows PC上にNextcloud AIOを立て、Tailscale経由でスマホやRaspberry Piからアクセスできるようにし、Raspberry Piをフォトフレーム化する手順メモです。

別記事で、作ったものの全体像や感想をまとめました。

この記事では、実際に再現するための設定・コマンド・つまずきポイントを中心に書きます。

家にWindows PC、Raspberry Pi、ディスプレイ、写真保存用HDDがあり、DockerやSSHを少し触れる人向けです。Ubuntuサーバーで組む方が素直ですが、今回はWindows 11 + Docker Desktopで構築しました。

家庭写真を扱うため、Nextcloudをインターネットへ直接公開せず、Tailscale経由でアクセスする構成にしています。

構成

スマホ / PC / Raspberry Pi
  -> Tailscale
  -> https://<machine-name>.<tailnet>.ts.net/

Windows 11 mini PC
  Docker Desktop
  Nextcloud AIO
  HDD: D:\home
    /picture
    /photoframe
    /family

Raspberry Pi
  rcloneでNextcloudの /photoframe を取得
  /home/<user>/Pictures/frame
  fehでスライドショー表示

以下、イメージ図。
image.png

前提

  • Windows 11
  • Docker Desktop導入済み
  • Tailscale導入済み
  • Raspberry PiはUbuntu Desktop系
  • Raspberry Pi公式7インチTouch Displayを使用
  • Raspberry Pi側ではSSHで操作できる
  • 各コマンド中の <user>, <machine-name>, <tailnet>, <nextcloud-user> は自分の環境に置き換える
  • パスワード、AIO passphrase、Nextcloudアプリパスワードは記事やリポジトリに保存しない

1. Nextcloud AIOを起動する

Nextcloud AIO(All-in-One)は、Dockerを使ってNextcloud本体や関連コンテナをまとめて管理する公式のデプロイ方法です。データベース、Redis、ApacheなどもAIO側で管理してくれるので、手動で個別コンテナを組み合わせるより始めやすいです。

今回は、Nextcloudをインターネットへ直接公開せず、Tailscale Serveの後ろに置きます。

そのため、AIOのApacheコンテナは 127.0.0.1:11000 で待ち受けるようにし、外部からはTailscaleのHTTPS URL経由でアクセスします。

PowerShellで以下を実行します。

docker run --init --sig-proxy=false `
  --name nextcloud-aio-mastercontainer `
  --restart always `
  --publish 8080:8080 `
  --env APACHE_PORT=11000 `
  --env APACHE_IP_BINDING=127.0.0.1 `
  --env NEXTCLOUD_MOUNT=/mnt/d/home `
  --volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config `
  --volume /var/run/docker.sock:/var/run/docker.sock:ro `
  ghcr.io/nextcloud-releases/all-in-one:latest

ポイント:

  • AIO管理画面は https://127.0.0.1:8080
  • Nextcloud本体は後で 127.0.0.1:11000 に出る
  • NEXTCLOUD_MOUNT は外部ストレージとして許可するホスト側パス
  • APACHE_IP_BINDING=127.0.0.1 にして、Nextcloud本体はローカルにだけ出す

各オプションの意味は以下です。

オプション 意味
--publish 8080:8080 AIO管理画面を開くためのポート
APACHE_PORT=11000 Nextcloud本体をAIO内のApacheコンテナから公開するポート
APACHE_IP_BINDING=127.0.0.1 Apacheコンテナをlocalhostにだけバインドする設定
NEXTCLOUD_MOUNT=/mnt/d/home Nextcloud外部ストレージとして使うホスト側パスを許可する設定
nextcloud_aio_mastercontainer:/mnt/docker-aio-config AIOの設定を保存するDocker volume
/var/run/docker.sock:/var/run/docker.sock:ro AIOが関連コンテナを作成・管理するために必要なDocker socket

APACHE_IP_BINDING=127.0.0.1 は、今回のように同じWindows上のTailscale Serveからだけアクセスさせる場合に使います。Nextcloud本体を直接外部公開しないための設定です。

Windows HDDパスの注意

この環境では、以下はNextcloudコンテナ内で空になりました。

/run/desktop/mnt/host/d/home

正しく見えたのは以下でした。

/mnt/d/home

環境差がありそうなので、AIOを本格設定する前にテストコンテナで確認すると安全です。

docker run --rm -v /mnt/d/home:/test alpine:latest ls -la /test

2. Tailscale Serveを設定する

Tailscaleがインストールされていなければ、公式ページからダウンロードしてインストールし、ログインします。

Tailscale管理画面で以下を有効化します。

  • MagicDNS
  • HTTPS Certificates

次にWindows側でTailscale Serveを設定します。

tailscale serve --bg --https=443 http://127.0.0.1:11000
tailscale serve status

期待値:

https://<machine-name>.<tailnet>.ts.net (tailnet only)
|-- / proxy http://127.0.0.1:11000

Nextcloud AIOのドメイン欄には、以下のようなTailscaleのFQDNを入力します。

<machine-name>.<tailnet>.ts.net

3. AIOでNextcloudを起動する

AIO管理画面を開きます。

https://127.0.0.1:8080

初回表示されるpassphraseは必ずパスワードマネージャーに保存します。再表示できないので注意します。

AIO管理画面でドメインを入力し、必要なコンテナを選択します。

今回の用途では、写真保存とフォトフレーム用途が主なので、まず軽めの構成にしました。

  • Nextcloud Hub: 有効
  • Imaginary: 有効
  • Office: 無効
  • ClamAV: 無効
  • Fulltextsearch: 無効
  • Talk: 無効

コンテナがすべてhealthyになるまで待ちます。

docker ps

4. Nextcloudの初期設定

Nextcloudにログインしたら、管理者の初期パスワードを変更します。

その後、普段使い用ユーザーを作成します。

例:

admin: 管理用
user: 普段使い用
family: 家族用

パスワードやpassphraseはリポジトリやメモファイルには保存せず、パスワードマネージャーで管理します。

5. 外部ストレージを追加する

Nextcloudの管理者設定から、外部ストレージを追加します。

前提として、Windows側のHDDには以下のようなフォルダを作っておきます。

例:

/picture    -> /mnt/d/home/picture
/photoframe -> /mnt/d/home/photoframe
/family     -> /mnt/d/home/family

外部ストレージの「制限する」は、その外部ストレージを誰のファイル一覧に表示するかの設定です。

例:

photoframe: user, family
family: user, family

通常の共有リンクとは別物です。

ユーザーごとにReadOnlyと編集可を細かく分けたい場合は、外部ストレージを直接見せるより、Nextcloud内部フォルダとして作って共有権限を設定する方が向いています。

今回の構成では、家族で触る共有・表示用フォルダとして /photoframe や /family を使う前提にしています。大事な元写真フォルダをそのまま全員に見せる場合は、権限設定を慎重に確認した方がよいです。

6. 外部ストレージを検証する

docker exec --user www-data nextcloud-aio-nextcloud php occ files_external:list
docker exec --user www-data nextcloud-aio-nextcloud php occ files_external:verify <mount-id>

必要に応じてスキャンします。

docker exec --user www-data nextcloud-aio-nextcloud php occ files:scan --path='<user>/files/picture'

写真が多い場合、サイズ表示が Pending になることがあります。
外部ストレージ検証がOKで、実ファイルが開けるなら、サイズ集計待ちの可能性が高いです。

7. Raspberry PiにTailscaleを入れる

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
tailscale status

自分の環境では、SSHから sudo tailscale up してもログインフローが進まず、Raspberry Piにディスプレイをつないで実行するとブラウザでログイン画面が出ました。そこでログインしました。

その後、Windows側のNextcloudマシンが tailscale status で見えればOKです。

8. Raspberry Piにrcloneを入れる

sudo apt update
sudo apt install -y rclone
rclone config

設定例:

n) New remote
name> nextcloud
Storage> webdav
url> https://<machine-name>.<tailnet>.ts.net/remote.php/dav/files/<nextcloud-user>/
vendor> nextcloud
user> <nextcloud-user>
password> <app-password>
bearer_token> 空Enter

Nextcloudの通常パスワードではなく、アプリパスワードを使います。

アプリパスワードは、Nextcloudの個人設定から発行します。通常のログインパスワードをrclone設定に入れない方が安全です。

9. フォトフレーム用フォルダを同期する

mkdir -p /home/<user>/Pictures/frame

dry-run:

rclone sync nextcloud:photoframe /home/<user>/Pictures/frame --dry-run

sync はNextcloud側にないファイルをRaspberry Pi側から削除します。Nextcloudを正とする運用なら sync でOKです。

初回や削除が不安な場合は、まず copy を使う方が安全です。

rclone copy nextcloud:photoframe /home/<user>/Pictures/frame --dry-run

本実行:

rclone sync nextcloud:photoframe /home/<user>/Pictures/frame --log-file=/home/<user>/photoframe-rclone.log --log-level INFO

削除を同期したくない運用なら、本実行も copy にします。

cron:

crontab -e
*/10 * * * * rclone sync nextcloud:photoframe /home/<user>/Pictures/frame --log-file=/home/<user>/photoframe-rclone.log --log-level INFO

copy 運用にする場合は、cron側も sync を copy に置き換えます。

ログ確認:

tail -n 50 /home/<user>/photoframe-rclone.log

10. fehでスライドショー表示する

fehは、画像を全画面表示できるツールです。写真をスライドショー表示するだけなら、おそらくこれが一番簡単でした。(今後、自作も含めて別のものに変えるかもしれません。)

Raspberry Pi側で、同期した写真を feh で全画面スライドショー表示します。

sudo apt install -y feh unclutter

起動スクリプト例:

mkdir -p /home/<user>/bin
nano /home/<user>/bin/start-photoframe.sh
#!/usr/bin/env bash
set -e

xset s off
xset -dpms
xset s noblank
unclutter -idle 0.5 -root &

exec feh --fullscreen --hide-pointer --slideshow-delay 20 --randomize --auto-zoom "$HOME/Pictures/frame"
chmod +x /home/<user>/bin/start-photoframe.sh
DISPLAY=:0 /home/<user>/bin/start-photoframe.sh

本体ディスプレイ側でスライドショーが表示されればOKです。

GUIログイン後に自動起動する場合は、デスクトップ環境の自動起動設定に登録します。Ubuntu Desktop系なら、~/.config/autostart/photoframe.desktop を作る方法が使えます。

mkdir -p /home/<user>/.config/autostart
nano /home/<user>/.config/autostart/photoframe.desktop
[Desktop Entry]
Type=Application
Name=Photoframe
Exec=/home/<user>/bin/start-photoframe.sh
X-GNOME-Autostart-enabled=true

環境によっては、自動ログイン設定も必要です。自分の環境では、ディスプレイマネージャーがLightDMだったため、LightDM側で自動ログインを設定しました。

cat /etc/X11/default-display-manager

LightDMの場合の例:

[Seat:*]
autologin-user=<user>
autologin-user-timeout=0
user-session=ubuntu

11. スクリーンロックと自動サスペンドを無効化する

フォトフレーム用途では、一定時間後にロック画面へ戻ったり、自動サスペンドしたりすると困ります。

SSHからGUIセッションを確認します。

who
id <user>
loginctl list-sessions

Ubuntu Desktopでは、スクリーンロックだけでなく電源管理側の自動サスペンドが残っていることがあります。

GUIユーザーが <user>、UIDが 1000 の場合は、SSHからGUIユーザーのDBusに対して gsettings を実行します。UIDが違う場合は /run/user/1000/bus の 1000 を読み替えます。

sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings get org.gnome.desktop.session idle-delay
sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings get org.gnome.desktop.screensaver lock-enabled
sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings get org.gnome.desktop.screensaver lock-delay
sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings get org.gnome.settings-daemon.plugins.power sleep-inactive-ac-type
sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings get org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout
sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings get org.gnome.settings-daemon.plugins.power idle-dim

フォトフレーム用途では以下のように無効化します。

sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings set org.gnome.desktop.session idle-delay 0
sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings set org.gnome.desktop.screensaver lock-enabled false
sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings set org.gnome.desktop.screensaver lock-delay 0
sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-type 'nothing'
sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout 0
sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings set org.gnome.settings-daemon.plugins.power idle-dim false

期待値:

uint32 0
false
uint32 0
'nothing'
0
false

X11側のスクリーンセーバー/DPMSも確認します。

sudo -u <user> DISPLAY=:0 XAUTHORITY=/home/<user>/.Xauthority xset q

以下のようになっていればOKです。

Screen Saver:
  timeout:  0
DPMS (Energy Star):
  DPMS is Disabled

もし有効になっている場合は、起動スクリプトにも入れている以下を実行します。

sudo -u <user> DISPLAY=:0 XAUTHORITY=/home/<user>/.Xauthority xset s off
sudo -u <user> DISPLAY=:0 XAUTHORITY=/home/<user>/.Xauthority xset -dpms
sudo -u <user> DISPLAY=:0 XAUTHORITY=/home/<user>/.Xauthority xset s noblank

12. ディスプレイ輝度を設定する

公式7インチTouch Displayは、そのままだとフォトフレームとして少し明るく感じることがあります。必要に応じて輝度を下げます。

バックライトデバイスを確認します。

ls /sys/class/backlight

公式7インチTouch Displayでは以下が見えました。

rpi_backlight

現在値を確認します。

for f in brightness actual_brightness max_brightness bl_power; do
  echo "$f: $(cat /sys/class/backlight/rpi_backlight/$f)"
done

max_brightness が 255 の場合、raw値 100 は約40%の明るさです。

手動で一時設定する場合:

echo 100 | sudo tee /sys/class/backlight/rpi_backlight/brightness

MATE Desktopでは、起動時にMATEの電源管理が明るさを上書きすることがあります。
SSHからGUIユーザーのDBusに対して、MATE側のAC電源時輝度を確認します。

sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings get org.mate.power-manager brightness-ac

brightness-ac はraw値ではなくパーセント指定です。
raw 100 / 255 相当にしたい場合は、約40%にします。

sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings set org.mate.power-manager brightness-ac 40.0

確認:

sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings get org.mate.power-manager brightness-ac
cat /sys/class/backlight/rpi_backlight/brightness
cat /sys/class/backlight/rpi_backlight/actual_brightness

期待値は、brightness-ac が 40.0、実際の輝度が 102 前後です。

MATEが起動時にどの値を設定しているかはログで確認できます。

journalctl -b | grep -i backlight

mate-power-backlight-helper --set-brightness 102 のようになっていれば、MATE側の設定が効いています。

13. 再起動後チェック

最後に、Windows側とRaspberry Pi側を再起動しても復帰できるか確認します。

Windows側:

docker ps
tailscale serve status

Raspberry Pi側:

tailscale status
tail -n 50 /home/<user>/photoframe-rclone.log
ls -lh /home/<user>/Pictures/frame | head
cat /sys/class/backlight/rpi_backlight/brightness
cat /sys/class/backlight/rpi_backlight/actual_brightness
sudo -u <user> DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus gsettings get org.mate.power-manager brightness-ac

Nextcloudアプリやブラウザから以下が開ければOKです。

https://<machine-name>.<tailnet>.ts.net/

まとめ

フォトフレームだけなら市販品を買う方が早いです。

ただ、NextcloudとTailscaleを組み合わせると、自宅HDD上の写真を家族で共有し、その一部をRaspberry Piに同期して表示する仕組みが作れます。

外部公開せずに使えるので、家庭写真を扱う構成としても扱いやすいです。

今回つまずいたポイントは、主に以下でした。

  • Windows + Docker Desktop環境で、HDDのパスをどうNextcloud AIOへ見せるか
  • Nextcloud外部ストレージの「制限する」の意味
  • Raspberry Pi側のrclone同期
  • GUIログイン後の自動起動
  • スクリーンロック、自動サスペンド、輝度設定

別の記事には、作った背景や全体像、使ってみた感想をまとめています。この記事は再現用の手順メモとして使う想定です。

2
3
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
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?