本記事執筆のきっかけ

Androidスマホと連携していたGoogleフォトの無料枠15GBに迫ってきたため、スマホで撮った写真や動画の別の保存先を考えなくてはならなくなりました。

クラウドサービスだと有料プランの加入が必要な場合が多いため、今回手元にあったRaspberry Piを使い、自前の写真サーバを構築してみました。

今回、以下のサービスを用い自前の写真サーバを構築した手順を記載します。

  • PhotoPrism:オープンソースの写真アプリ。AIが搭載されており、高度な検索やタグ付け等ができる。
  • Tailscale:WireGuardプロトコルを使用したVPNの構築を可能とするサービス。無料プランでも100台分のデバイスでVPNを構築できる。

ゴールとしては、AndroidスマホからVPNを経由して、自宅外からもRaspberry Pi上の写真サーバへ閲覧・ファイルアップロードができることを目指しました。

環境

  • Raspberry Piのモデル
cat /proc/device-tree/model
Raspberry Pi 4 Model B Rev 1.5
  • OS
lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 11 (bullseye)
Release:        11
Codename:       bullseye
$ getconf LONG_BIT
32
  • 画像を格納するストレージ

    • 手元にあったSanDiskの256GBのUSBを使用(ある程度の容量を確保できるなら何でも可)
  • その他前提条件

    • Raspberry pi上にDockerとDocker Composeの導入が完了していること

PhotoPrismの構築

画像格納用ストレージの設定

画像格納用のストレージとしてUSBを使用するため、自動マウントの設定を行います。

  • USBデバイスの確認
sudo fdisk -l
Disk /dev/sda: 232.97 GiB, 250148290560 bytes, 488570880 sectors
Disk model:  SanDisk 3.2Gen1
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x08286ff4

→構築時、/dev/sdaとして認識されていた

  • パーティションの作成
sudo fdisk /dev/sda

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 空欄のままEnter
First sector (2048-488570879, default 2048): 空欄のままEnter
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-488570879, default 488570879): 空欄のままEnter
  • ファイルシステムの作成
sudo mkfs.ext4 /dev/sda1
  • 自動マウントの設定
blkid /dev/sda1
/dev/sda1: UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="08286ff4-01"

→UUIDを控えておく

sudo vim /etc/fstab
UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"     /media  ext4    defaults        0       0

→事前に調べたUUIDを指定して/mediaディレクトリにマウントさせる設定を記載

  • USBのマウント
sudo mount -a
df -h /media

→/mediaが認識されていればOK

PhotoPrismの構築

Docker Composeを用いてPhotoPrismを構築します。

compose.ymlは配布されているものを利用します。

  • compose.ymlの取得
wget https://dl.photoprism.app/docker/armv7/docker-compose.yml

基本はダウンロードしたymlファイルを活用し、変更が必要な箇所だけ修正していきます。

  • PhotoPrismのログインユーザ/パスワードの設定
vim docker-compose.yml
services:
  photoprism:
    environment:
      PHOTOPRISM_ADMIN_USER: "admin"                 # admin login username
      PHOTOPRISM_ADMIN_PASSWORD: "insecure"          # initial admin password (8-72 characters)

PHOTOPRISM_ADMIN_USERでログインユーザ名、PHOTOPRISM_ADMIN_PASSWORDでパスワードを任意のものに変更します。

  • 画像格納用ディレクトリの設定
vim docker-compose.yml
volumes:
      # "/host/folder:/photoprism/folder"                # Example
      - "/media/images:/photoprism/originals"               # Original media files (DO NOT REMOVE)
      # - "/example/family:/photoprism/originals/family" # *Additional* media folders can be mounted like this
      # - "~/Import:/photoprism/import"                  # *Optional* base folder from which files can be imported to originals
      - "./storage:/photoprism/storage"                  # *Writable* storage folder for cache, database, and sidecar files (DO NOT REMOVE)

必要に応じて、PhotoPrismコンテナのoriginalsとstorageディレクトリのバインドマウントの設定を変更します。

今回は、originalsディレクトリをローカルで認識させたUSB内の/media/imagesディレクトリと連携する設定としました。

PhotoPrism側のそれぞれのディレクトリの用途は以下の通りです。

ディレクトリ 用途
/photoprism/originals 画像や動画を格納される
/photoprism/storage 主に画像や動画のサムネイルが格納される
  • PhotoPrismコンテナの起動
docker compose up -d
  • PhotoPrismへのアクセス

ブラウザでhttp://localhost:2342へアクセスし、compose.ymlで設定したユーザ、パスワードを入力する login

  • 「settings」で「Language」を日本語に変更する change_language

  • PhotoPrismコンテナのoriginalsディレクトリ(ホストOS側の/media/images)に適当な画像ファイルを格納する

  • 「ライブラリ」> 「インデックス」タブより「開始」をクリックする index

  • 「検索」欄に画像が表示されていればOK phptolist

Tailscaleの導入

Tailscaleへのサインアップ

  • Tailscaleの公式サイトにアクセスする(Raspberry Pi以外のPCでもOK)

  • 「Get Started」をクリックし、Google等の任意のアカウントでサインアップする

  • 今回、登録するプランはPersonalプランとする

AndroidスマホにTailScaleをインストールする

  • AndroidスマホでGoogle Playを開き、Tailscaleアプリをインストールする

  • 事前にサインアップした時と同じアカウントでTailscaleに接続を行う

  • アプリが開き、スマホの端末名とグローバルIPアドレス(100.x.y.zの範囲)が表示されていればOK

Raspberry PiにTailscaleをインストールする

  • Raspberry Piで以下のコマンドを実行する
curl -fsSL https://tailscale.com/install.sh | sh
  • 以下のコマンドを実行し、Tailscaleを起動する
sudo tailscale up

To authenticate, visit:

        https://login.tailscale.com/a/xxxxxxxxxxxxx

→コマンドを実行すると認証用のURLが表示されるため、ブラウザで開きサインアップできれば、「Success.」と表示される

  • この時点でTailscaleの管理コンソールにアクセスし、「Machine」タブでスマホとRaspberry piが登録されていればOK machine_list

ここまでで、スマホのブラウザでhttp://<Raspberry Piに割り振られたTailscaleのIPアドレス>:2342へアクセスすると、VPN経由でPhotoPrismにアクセスできるようになりました。

Tailscale Serveの設定

現時点だと、スマホからPhotoPrismへVPN接続を行うことができていますが、IPアドレスを指定したHTTPでの接続しかできません。

そこでHTTPSでの接続を実現するために、今回はTailscale Serveという機能を使って、Tailscaleドメイン(tail-NNNN.ts.netのような形)で接続できるように設定します。

Tailscale Serveとは、Tailscaleに登録したデバイス間のネットワーク(tailnet)でWebサーバのようなサービスを提供できる機能で、他のデバイスからのトラフィックをローカルのサービスにルーティングできます。

HTTPS証明書の有効化

  • Tailscaleの管理コンソールで「DNS」>「HTTPS Certificates」欄でHTTPSが有効になっていることを確認する https_certificates 有効になっていない場合は、「Enable HTTPS」をクリックする。

Tailscale Serveの設定

  • Raspberry Piで以下のコマンドを実行する
sudo tailscale serve --bg http://127.0.0.1:2342
Available within your tailnet:

https://xxx.tailxxxxxx.ts.net/
|-- proxy http://127.0.0.1:2342

Serve started and running in the background.
To disable the proxy, run: tailscale serve --https=443 off

→上記コマンドを実行することで、表示されたURLにアクセスすると、Raspberry Pi上の2342ポートに転送され、PhotoPrismにアクセスできるようになる。

ここまでで、PhotoPrismにHTTPSで接続できるようになりました。

Photo Uploader for PhotoPrismの導入

最後に、PhotoPrismへ画像や動画をアップロードする方法を確立します。

今回のユースケースとしては、Androidスマホからファイルをアップロードしたいため、「Photo Uploader for PhotoPrism」というアプリを利用します。

  • AndroidスマホでGoogle Playを開き、Photo Uploader for PhotoPrismをインストールする

  • アプリを開き、「Settings」から以下の情報を登録する

    • Your Server:Raspberry Piに割り当てられたTailscaleドメイン
    • Username:PhotoPrismのログインユーザ
    • Password:PhotoPrismのパスワード settings

ここまでで、メイン画面でアップロードしたい写真や動画を選択し、「Upload」ボタンをクリックすると、Raspberry Pi上のPhotoPrismに送信できるようになりました。 photo_upload

最後に

PhotoPrismやTailscaleを利用して自宅外からもアクセスできる写真サーバを簡単に作成することができました。

今後、NextCloudを利用したファイル連携や独自ドメインでの接続設定等、作りこんでいきたいと思います。

参考にさせていただいたサイト