さくらのVPSで試す、軽量ActivityPub実装「snac」によるセルフホストSNS構築

はじめに

鹿児島らぐというLinux User Groupで月イチを目処に勉強会を行っています。現在は主にオンラインで活動しており、オープンソースのソフトウェアをVPSにセルフホストしてそれを利用してオンライン勉強会をしています。

このコミニュティのアナウンスを何らかのサービスやソフトウェアで行いたいと思っていたのですが、最近のSNSなどのサービスはアカウントを作成してもらい、ログイン状態でないとコンテンツが確認できなかったり年齢制限があったりします。また、アカウントの運用を始めてもサービスの何らかの制限でアカウントが削除されたり、検索結果に出なくなったりと運用が難しいです。

e-mailのようにオープンなプロトコルで複数の実装のあるようなものであれば、もしアカウントが停止されるようなことがあっても利用サービスを移動したりセルフホストすることも可能です。
オープンで複数の実装があるものとして、ActivityPubやMatrixがあります。Matrixは基本的に利用者もアカウントの作成が必要ですが、ActivityPubはウェブブラウザがあれば閲覧できます。
ActivityPubのOSS系のインスタンスでアカウントを取得して運用することも考えましたが、どうせならセルフホストしたいなと思っていました。しかしActivityPubのメジャーな実装は結構重いので、現在他の用途でも利用しているVPSでの運用は難しそうです。軽量な実装でもメモリが512MBくらいは必要そうです。コミニュティのためのインスタンスならありかなと思いますが、アナウンスのためだけにはコストが大きく感じます。

OSS系のActivityPubインスタンスでアカウントを取得するしかないかなと思っていたのですが、最近snacという軽量なActivityPubの実装を見つけました。

snacについて

snacはシンプルでミニマムなActivityPubインスタンスです。C言語で実装されており、ライセンスはMITライセンスです。

次のような特徴があります。

  • 軽量で依存関係が最小限
  • マルチユーザー対応
  • コマンドラインで操作可能
  • データベース/JavaScript/Cookiesなし
  • Mastodon APIのサポート(Mastodonアプリケーションが利用可能)

リポジトリを見ていると開発も活発です。
snacを利用しているインスタンスとしてBSD Cafeなどがあります。
また、snacの有料ホスティングサービスもあります。($2.75/月)

snacのソースコードは以下のサイトにて公開されています。

snacを試してみる

まずはどんな感じか把握するために、ローカル環境で動かしてみました。

ソースコードからのビルド時には、今回試したDebian 13 trixie amd64では libssl-dev libcurl4-openssl-dev パッケージも必要でした。
makeを実行するとsnacというバイナリが生成されます。 snac <サブコマンド> で様々な操作ができます。詳細は -h オプションで確認できます。

$ sudo apt install libssl-dev libcurl4-openssl-dev
$ git clone https://codeberg.org/grunfink/snac2
$ cd snac2
$ make 

init コマンドにsnacデータ格納パスを指定して初期設定を行います。いくつかの質問に答える必要があります。

$ ./snac init ~/snac-data/
Network address or full path to unix socket [127.0.0.1]: 
Network port [8001]:
Host name: 127.0.0.1:8001
URL prefix:
Admin email address (optional):
Done.

Wanted web UI language files (.po) must be copied manually to /tmp/snac2/lang

サーバー設定ファイルの server.json を編集します。 "protocol""http" に変更します。

$ vi ~/snac-data/server.json

次にアカウントを作成します。ここでは matoken を作成しています。初期パスワードが出力されるのでメモしておきます。

$ ./snac adduser ~/snac-data/ matoken
Creating RSA key...
Done.

User password is Y17pvR3CSOovUFhx

Go to http://127.0.0.1/matoken and continue configuring your user there.

httpd コマンドでsnacのデーモンを起動します。ウェブブラウザでアクセスすることで確認できます。

$ ./snac httpd ~/snac-data/
snacインスタンスホーム画面
snacユーザー画面

左上の private リンクを押すことで認証画面になります。パスワードはアカウント作成時に表示されたパスワードです。認証後、投稿や各種設定などが可能になります。

snacログイン後画面

snacコマンドでも投稿が可能です。

$ ./snac note ~/snac-data matoken "post from terminal"
07:39:24 [matoken] enqueue_message http://127.0.0.1:8001/matoken/p/1760827164.098584/Create

snacのメモリ利用量

自分のVPS環境でネックになるのはメモリなのでメモリ利用量を確認してみます。

少し触ったあとにpsコマンドで見ると13MBほどでした。

$ ps aux | pee "head -1" "grep ./snac | grep -v grep"
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
matoken  3308173  0.0  0.0 613476 13092 pts/11   Sl+  07:22   0:00 ./snac httpd /tmp/snac

負荷をかけてみるとどうかなと以下のようなscriptで画像付き投稿を10分おきに1週間ほど投稿し続けたあと同様に確認するとメモリ利用量は23MB程(23080)になりました。

OUT="`date +%s`.jpg"
URL="`yt-dlp -f best --get-url https://www.youtube.com/nasa/live`"
ffmpeg -i $URL -vframes 1 -q:v 2 -y /tmp/$OUT
snac note ~/snac-data/ matoken 'https://www.youtube.com/nasa/live' /tmp/$OUT
rm /tmp/$OUT

サーバー間の通信などは行っていない状態ですが、このくらいなら現在動作中のVPSに追加しても問題無さそうです。

Debianパッケージ版snac

そういえばDebianパッケージにsnacパッケージはないかなと確認するとoldstable-backports(Debian 12 bookworm-backports)以降にsnac2パッケージが存在するようです。

Debian 13でのバージョンは 2.75 で少し古いですが、 backportsでは 2.84 でsnacの最新に追従していそうです。運用の手間のことを考えるとパッケージ版を使ったほうが楽そうです。

$ rmadison snac2
snac2      | 2.75-2~bpo12+1 | oldstable-backports       | source, amd64, arm64, armel, armhf, i386, mips64el, mipsel, ppc64el, s390x
snac2      | 2.75-2~bpo12+1 | oldstable-backports-debug | source
snac2      | 2.75-2         | stable                    | source, amd64, arm64, armel, armhf, i386, ppc64el, riscv64, s390x
snac2      | 2.84-2~bpo13+1 | stable-backports          | source, amd64, arm64, armel, armhf, i386, ppc64el, riscv64, s390x
snac2      | 2.84-2~bpo13+1 | stable-backports-debug    | source
snac2      | 2.84-2         | testing                   | source, amd64, arm64, armhf, i386, ppc64el, riscv64, s390x
snac2      | 2.84-2         | unstable                  | source, amd64, arm64, armhf, i386, ppc64el, riscv64, s390x
snac2      | 2.84-2         | unstable-debug            | source

本番環境にsnacを設置

今回はさくらインターネットさんにコミニュティ支援にて提供いただいているさくらのVPS 1G上のDebian GNU/Linux 13 trixe amd64環境上にsnacをインストールしました。

以下のような手順で導入しました。
今回はsnac用にサブドメインを用意してそこに設置することにしました。サブドメインを使わなくても既存のドメインのサブディレクトリ以下に設置することも可能です。(Debianパッケージ版の既定値の動作です)

  • DNSで専用のサブドメインを設定(ここでは割愛)
  • SSL証明書の取得
  • snacパッケージの導入
  • snac設定
  • httpd(proxy)設定

SSL証明書の取得

Let's Encryptでcertbot コマンドを利用して証明書を取得しました。

$ sudo certbot certonly -d <SNAC_DOMAIN>

snacパッケージの導入

Debianでは snac2 というパッケージ名でパッケージングされています。

$ sudo apt install snac2

snac2パッケージの主なファイル、ディレクトリです。Debian環境に合わせてあります。

  • /usr/bin/snac snacコマンド
  • /etc/apache2/conf-available/snac2.conf snacのapache2向け設定( /social で設定されているのでそのままではなく参考に )
  • /usr/share/doc/snac2/examples/nginx-snac2.conf nginx 向け設定
  • /usr/lib/systemd/system/snac2.service systemd用サービスファイル
  • /var/lib/snac2 snacデータディレクトリ
  • /etc/snac2/server.json snac設定

snacユーザーとして debian-snac も作成されます。snacデーモンはこのユーザーとして実行されます。

snacの設定

snac2パッケージを導入するとsnacの設定が行われ、snacが起動してしまうので一旦停止して自分好みの設定でやりなおします。

$ sudo service snac2 stop
$ sudo rm /var/lib/snac2/*
$ sudo -u debian-snac snac /var/lib/snac2 init

initコマンド実行後、設定ファイル( /etc/snac2/server.json )を確認、編集します。

  • "host" がsnac用のドメインになっているか
  • "prefix""" になっているか
  • "title" に好みのインスタンスタイトルを設定

snacユーザ登録

adduserコマンドでユーザーを追加します。ここではまず仮のユーザーを登録するのをおすすめします。snacやhttpdの設定を間違えるとリモートインスタンスに誤った情報がキャッシュされてしまい困ることがあります。

$ sudo -u debian-snac snac adduser /var/lib/snac2 testuser

snac起動

snacデーモンを起動します。

$ sudo service snac2 start

httpd(proxy)設定

今回はapache2 httpdを利用しました。Debianのsnac2パッケージにはnginxのサンプルも同梱されています。また、snacのREADME.mdの中のLinks of Interestを見るとその他の環境の設定例もあり参考になります。

apache2 httpdの設定はsnac2パッケージの /etc/apache2/conf-available/snac2.conf を参考に /etc/apache2/sites-available/nnn-<SNAC_DOMAIN>.conf を作成しました。基本的に自分のドメイン合わせて書き換えて、 /social/ に書き換えました。

設定を有効にして設定を読み込みして反映します。

$ sudo a2ensite nnn-<SNAC_DOMAIN>.conf
$ sudo systemctl reload apache2

ウェブブラウザでアクセスして動作確認をします。他のインスタンスとフォローし合って投稿が流れてくるか確認しました。

snacのデバッグ

設定が間違っていたりして期待した動きにならない場合デバッグが必要です。httpd側のログの他にsnacのログが見たいですがログファイルは作成されないようです。コンソールにログが出力されるのでこれを確認してデバッグできます。
snacのデバッグ時には設定ファイルの dbglevel の項目を規定値の 0 から増やしていくことでログレベルを上げることが出来ます。範囲は 0-3 のようです。

Mastodonクライアントの利用

snacのウェブインターフェイスはシンプルでJavaScriptの動作しない環境でも動作します。でもそれでは物足りない場合、snacはビルド時に無効にしなければMastodon APIが利用できるので、各種マストドンクライアント経由でsnacを利用することができます。例えば自分が少し試したところではウェブクライアントのElk、Pinafore。AndroidクライアントのFedilab、Pachli。cli/tuiクライアントのtootで投稿の取得や投稿が出来ました。

snacはMastodon APIの全てに対応しているわけではないので動作しないクライアントや機能もあります。

tootで動作している画面

snacアカウントのウェブページへの埋め込み

snacで投稿した内容をウェブページに埋め込むと便利そうなのではじめRSSを埋め込もうかと思ったのですが、「Mastodon embed timeline widget」を使うとMastodonアカウントをMastodon API経由でウェブページに埋め込みができるようなので試してみました。

以下のファイルを対象ページに埋め込むことで実現できるようです。

  • dist/mastodon-timeline.min.css
  • dist/mastodon-timeline.umd.js

もしくは以下のCDNにも置いてあるのでこちらを使わせてもらうと手軽に利用できます。

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@idotj/mastodon-embed-timeline@4.7.0/dist/mastodon-timeline.min.css" integrity="sha256-Qi3H+bdH6RuMuyR1trAlG5bMWJGl9y3jPiTc1PWQFpI=" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/@idotj/mastodon-embed-timeline@4.7.0/dist/mastodon-timeline.umd.js" integrity="sha256-p6Xvd6OVSoasRG8M7ct20nnzGdnFMVapWyp9PGpW2Uo=" crossorigin="anonymous"></script>

「Mastodon embed timeline widget」は埋め込み方がいくつか選べます。リポジトリの examples/ 以下に例がいくつかあるのでこれを書き換えて動作を確認すると便利です。今回は「Profile timeline」を使い、件数や色をカスタマイズしました。
動作確認ができたら以下のようなコードを投稿を埋め込みたい場所に書きます。

<h1>ActivityPub</h1>
<p>
<div id="mt-container" class="mt-container">
      <div class="mt-body" role="feed">
              <div class="mt-loading-spinner"></div>
                </div>
</div>
    <script src="https://cdn.jsdelivr.net/npm/@idotj/mastodon-embed-timeline@4.7.0/dist/mastodon-timeline.umd.js"></script>
    <script src="../dist/mastodon-timeline.umd.js"></script>
    <script>
      const myTimeline = new MastodonTimeline.Init({
        instanceUrl: "https://snac.kagolug.org", <!-- インスタンスurl -->
        timelineType: "profile",
        userId: "953f1cae317ccce78e5315d36cad2ab3", <!-- ユーザーID APIで取得する -->
        profileName: "@info", <!-- 対象ユーザー -->
        defaultTheme: "light", <!-- テーマ -->
        maxNbPostShow: "5", <!-- 表示件数 -->
        dateFormatLocale: "ja-JP", <!-- 日付の言語 -->
      });
    </script>

userId は以下のようなコマンドで確認できます。ドメインを調べたいものに書き換え、 acct= の後ろに調べたいアカウントを指定してください。

$ curl -s "https://snac.kagolug.org/api/v1/accounts/lookup?acct=info" | jq .id
"953f1cae317ccce78e5315d36cad2ab3"

snacのバックアップ

snacはデータベースもなくファイルベースなので簡単です。ただし、snacのデータはハードリンクを利用するのでハードリンクを保持するよう気をつけてください。GNU tarでは標準で保持すると思います。

バックアップ時はダウンタイムが発生しますがsnacのデーモンを停止した状態でバックアップすると確実だと思います。

$ sudo service snac2 stop 
$ sudo -u debian-snac tar cvf backup.tar --check-links /var/lib/snac2
$ sudo service snac2 start
$ zstd backup.tar && rm backup.tar

さらに少リソースに?

snacはデーモン以外にFastCGIでも動作します。アクセスも投稿も少ないと思うのでFastCGIでの動作にしたほうが少リソースになると思います。他にhttpdとして現在Aapache2 httpdを利用しているのですが、現在snac以外は静的サイトをホストしているだけなのでlighttpdなどの軽量なhttpdに切り替えても良さそうです。
さらにテストとしてOpenBSDで動作させるとメモリ利用量が半分以下になったのでOSをOpenBSDなどに変更すると消費メモリは減りそうです。でもLinux User Groupのサーバーなので多分このサーバーではやらないと思います。

おわりに

今回コミニュティのアナウンスのためにsnacというActivityPubインスタンスを設定してみました。x.comなどと違いウェブブラウザ(w3mなどのテキストブラウザでもOK)があれば閲覧できますし、RSSアグリゲーターでも購読でき、もちろんActivityPubでの購読も出来ます。さらに別のツールを使い、既存のウェブページへの埋め込みも出来、一通りやりたいことは出来ました。

今回アナウンス向けに設定しましたが、少リソースで動作するので少人数のコミニュティや個人向けのActivityPubインスタンスとして利用するのにもいいと思います。

もしこの記事を見て興味を持ってもらえたら嬉しく思います。

この記事は鹿児島Linux勉強会 2025.10で発表した資料を元に加筆修正しました。