概要

systemcontroller は Town OS の中核となるバックエンドサービスです。 Echo v5 を基盤とし、本番環境ではポート 5309(TCP)または Unix ドメインソケットで待ち受けます。リクエストとレスポンスのボディはすべて JSON です。 エラーは RFC 9457application/problem+json)に従います。

CORS は開発用に有効になっています。本番環境では、API は UI と同じオリジンで提供されます。

認証

ユーザー名とパスワードを添えて POST /account/authenticate を呼び出して 認証します。レスポンスには Bearer トークンが含まれるので、以降のリクエストに含めてください。

Authorization: Bearer <token>

セッションは 7 日間操作がないと期限切れになります。認証レベルは 5 種類あります。

レベル説明
公開トークンは不要です。
認証済み有効なセッショントークンであれば何でも構いません。
管理者管理者アカウントに属するセッショントークン。
グラントアカウントに与えられた個別のグラントが、管理者でない利用者を通します。オブジェクトストレージのエンドポイントはオブジェクトストレージのグラントを、ピア登録は wireguard のグラントを使い、ネットワークごとの範囲と各ピアの所有関係はハンドラー自身が確認します。
Localhostループバックからのリクエストは認証なしで通ります。ループバックに到達できること自体が、その機器の上にいることを意味するからです。それ以外の送信元には、バッジの隣に並ぶレベルが必要です。コントローラー自身のツールが読み取る systemd のユニットとログのエンドポイントで使われています。

パーティションの内部にあるエンドポイントは管理者に限られていませんが、オブジェクトストレージの パーティションを作ることだけは管理者に留保されています。パーティションは権限ツリーの根であり、 クォータ付きの btrfs サブボリュームを確保するからです。グラントが許すのはパーティションの中にいる 利用者を扱うことであって、そのパーティションが存在すべきかどうかを決めることではありません。

ページ送り

一覧を返すエンドポイントはすべて、次のクエリパラメーターを受け付け、共通の エンベロープを返します。

パラメーター説明
sort_bystring並べ替えに使うフィールド名。
sort_orderstringasc または desc
limitint1 ページあたりの件数(既定は 20)。
offsetintページ送りのオフセット。
searchstringすべての文字列フィールドに対する、大文字小文字を区別しない部分一致。

レスポンスのエンベロープ

{
  "entries":     [...],
  "has_more":    true,
  "total_pages": 5,
  "total_count": 97
}

ステータス

GET /status/ping 公開

ヘルスチェックとシステムの概要です。未認証の呼び出し元には statusneeds_setup だけの最小限のレスポンスが返ります。認証済みの呼び出し元には、 ファイルシステム数、パッケージ数、ユニットの状態のまとめ、ディスク使用量、 外部・内部 IP、アップグレードの有無を含む、ダッシュボード用の完全なペイロードが返ります。

アカウント

POST /account/authenticate 公開

ユーザー名とパスワードで認証します。セッショントークンとアカウントのオブジェクトを返します。

フィールド説明
usernamestring必須。 アカウントのユーザー名。
passwordstring必須。 アカウントのパスワード。
POST /account/create 公開 / 管理者

新しいアカウントを作成します。ブートストラップモード(有効な管理者アカウントが 1 つも存在しない状態)では、このエンドポイントは公開です。それ以外では管理者としての 認証が必要です。最初に作成されたアカウントが管理者になります。パスワードは 8 文字以上に してください。メールアドレス、電話番号、氏名は必須です。

フィールド説明
usernamestring必須。
passwordstring必須。 8 文字以上。
emailstring必須。
phonestring必須。
real_namestring必須。
adminbooleanそのアカウントに管理者権限を与えるかどうか。
POST /account 認証済み

ユーザー名でアカウントを 1 件取得します。リクエストボディ: {"username": "alice"}

GET /account 認証済み

すべてのアカウントを一覧します。ページ送りのパラメーターに対応しています。

POST /account/update 認証済み

アカウントのフィールドを更新します。対象を特定するために username を送り、 passwordemailphonereal_nameadmin を任意に組み合わせた fields オブジェクトを渡します。 指定したフィールドだけが変更されます。

GET /account/me 認証済み

Authorization ヘッダーのトークンに紐づくユーザー名を返します。

GET /account/sessions 認証済み

認証済みユーザーの有効なセッションをすべて一覧します。各セッションには ID、 ユーザー名、作成時刻、最終利用時刻が含まれます。

POST /account/session/revoke 認証済み

ID を指定してセッションを失効させます。リクエストボディ: {"session_id": "..."}

POST /account/disable 管理者

アカウントを無効にします。リクエストボディ: {"username": "bob"}

POST /account/enable 管理者

無効にしたアカウントを再び有効にします。リクエストボディ: {"username": "bob"}

ストレージ

POST /storage 認証済み

ファイルシステムを一覧します。ページ送りのパラメーターに加えて、リクエストボディで 任意の name(前方一致のフィルター)と stateuserinstalleduninstalled)を受け付けます。

POST /storage/create 認証済み

新しい btrfs のサブボリュームを作成します。name と、任意で quota(バイト)を送ります。クォータが 0 または未指定の場合は、 システムの既定値(50 GB)が使われます。予約された名前 (installeduninstalledarchives)は拒否されます。

POST /storage/modify 認証済み

既存のファイルシステムを変更します。対象を特定するために name を送り、 更新後の namequota を含む filesystem オブジェクトを渡します。

POST /storage/remove 認証済み

ファイルシステムを削除します。リクエストボディ: {"name": "mydata"}

POST /storage/upload-archive 管理者

アーカイブをアップロードし、対象のサブボリュームへ展開します。subvolume の フィールドと archive のファイルを含む multipart/form-data を 受け付けます。対応形式は .tar.gz.tgz.tar.bz2.tbz2.tar.xz.txz.tar.zip.7z です。

フィールド説明
subvolumestring必須。 展開先のサブボリュームのパス。
archivefile必須。 アップロードするアーカイブファイル。
subpathstring任意。ボリューム内の展開先の相対パス。必要に応じて作成されます。
stop_servicestring任意。展開前に停止し、完了後に再起動する systemd ユニット名。
設定既定値説明
max_archive_size1 GBアップロードの最大サイズ。
archive_unpack_timeout600 秒展開にかけられる最大時間。
POST /storage/download-archive 管理者

サブボリュームの内容をアーカイブとしてダウンロードします。指定された形式で ストリーミングされたアーカイブを返します。

フィールド説明
subvolumestring必須。 取得元のサブボリュームのパス。
pathsstring[]任意。サブボリューム内で含めたい特定のパスの配列。
stop_servicestring任意。アーカイブ作成中に停止し、完了後に再起動する systemd ユニット名。
formatstring任意。圧縮形式: tar.gz(既定)、tar.bz2tar.xz
filenamestring任意。ダウンロードするファイルのベース名。サーバーが適切な拡張子を付けます。既定は download です。
POST /storage/package-volumes 認証済み

パッケージのボリュームをパッケージごとにまとめて一覧します。アンインストール済みの ボリュームを含めることもできます。

POST /storage/remove-package-volume 管理者

内部名を指定して、特定のパッケージのボリュームを削除します。

POST /storage/remove-package-volume-group 管理者

内部名を一つずつ指定して消していく代わりに、一つのパッケージに属するボリュームを 一度の呼び出しですべて削除します。

リポジトリ

GET /repository 認証済み

設定済みのパッケージリポジトリを、名前、URL、エラーの状態とともにすべて一覧します。 ページ送りのパラメーターに対応しています。

POST /repository/add 認証済み

新しいパッケージリポジトリを追加します。すぐに更新が実行されます。

フィールド説明
namestring必須。 リポジトリの表示名。
urlstring必須。 リポジトリの git URL。
usernamestring任意。プライベートリポジトリ用の認証ユーザー名。
passwordstring任意。プライベートリポジトリ用の認証パスワード。
POST /repository/remove 認証済み

名前を指定してリポジトリを削除します。すぐに更新が実行されます。 リクエストボディ: {"name": "my-repo"}

POST /repository/move 管理者

リポジトリを 0 始まりの新しい位置へ並べ替えます。パッケージ名が衝突した場合、 後のリポジトリが先のものを上書きします。 リクエストボディ: {"name": "my-repo", "position": 0}

POST /repository/refresh 認証済み

すべてのリポジトリのメタデータを直ちに更新します。成功時は空のボディを返し、 失敗したものがあれば、リポジトリ名とエラー文字列を対応づけた JSON オブジェクトを返します。

パッケージ

GET /packages 認証済み

すべてのリポジトリにまたがって、利用できるパッケージを一覧します。各エントリーには リポジトリ、名前、バージョン、説明、supplies のタグ、インストール状況、 アップグレードの有無が含まれます。ページ送りのパラメーターに対応しています。

GET /packages/by-repo 認証済み

リポジトリごとにまとめてパッケージを一覧します。任意の search クエリ パラメーターを受け付けます。{"repo": "...", "packages": [...]} のグループの配列を返します。

GET /packages/installed 認証済み

インストール済みパッケージの識別子を一覧します。ページ送りのパラメーターに対応しています。

POST /packages/installed/info 認証済み

インストール済みパッケージの詳細情報を取得します。reponameversion を送ります。質問、利用者の回答、ノート、ノートの型を返します。

POST /packages/responses 認証済み

インストール済みパッケージについて保存された質問の回答を取得します。reponameversion を送ります。回答のキーと値のマップを返します。

POST /packages/versions 認証済み

パッケージの利用できるバージョンを一覧します。リクエストボディ: {"name": "nginx"}。 バージョン識別子の文字列配列を返します。

POST /packages/children 認証済み

子パッケージを一覧します。reponame を送ります。文字列の配列を返します。

POST /packages/questions 管理者

パッケージのインストール時の質問を取得します。リクエストボディ: {"name": "nginx"}。 質問のキーと {"query": "...", "type": "..."} の対応を返します。

POST /packages/questions/identity 管理者

特定のバージョンのパッケージの質問を取得します。reponameversion を送ります。

POST /packages/oauth/start 管理者

oauth の質問について OAuth のデバイスフローを開始します。reponameversionquestion を送ります。システム コントローラーがフローの開始ステップを提供元に対して実行し、flow_idapprove_url(利用者のブラウザーで開きます)、任意の user_code、 そしてポーリングの間隔である interval_ms を返します。

提供元の URL は Town OS ではなくパッケージ側から来るものなので、呼び出す前に 検証されます。https のみで、ホスト自身のネットワーク上のアドレスは 決して許されません。

POST /packages/oauth/poll 管理者

上で開始したフローをポーリングします。flow_id を送ります。 status を返し、利用者がまだ承認していなければ pending、 承認済みなら token とともに approved、フローがタイムアウトしたか トークンをすでに取得済みなら expired になります。フローは 1 回限りです。 取得したトークンは、入力された回答とまったく同じように、その質問の回答として /packages/install に送信します。

POST /packages/install-preview 管理者

確定する前に、インストールで何が行われるかをプレビューします。reponameversion を送ります。ボリュームの詳細、ポートマッピング、 ディスク使用量、クォータの情報、アップグレード元のバージョン、そして人が読める 要約を返します。

POST /packages/install 管理者

パッケージをインストールします。

フィールド説明
repostring必須。 リポジトリ名。
namestring必須。 パッケージ名。
versionstring必須。 インストールするバージョン。
responsesobject必須。 インストール時の質問へのキーと値の回答。
reuse_volumesboolean以前のインストールの既存データボリュームを再利用します。
import_from_versionstringアップグレード時にボリュームを取り込む元のバージョン。
POST /packages/uninstall 管理者

パッケージをアンインストールします。reponameversion と、関連データを削除する場合は任意の purge_volumes(boolean)を送ります。

POST /packages/disable 管理者

インストール済みパッケージを無効にします(サービスを停止します)。reponame を送ります。

POST /packages/enable 管理者

無効にしたパッケージを再び有効にします(サービスを開始します)。reponame を送ります。

POST /packages/purge-volumes 管理者

インストール済みパッケージのデータボリュームをすべて削除します。reponame を送ります。

POST /packages/uninstalled-volumes 管理者

以前のインストールから残ったボリュームがあるかを確認します。reponame を送ります。has_uninstalled_volumesuninstalled_versionsinstalled_versions を返します。

POST /packages/purge-uninstalled-volumes 管理者

以前アンインストールしたバージョンから残っているボリュームを削除します。 reponame を送ります。

GET /packages/upgrades 認証済み

インストール済みパッケージで利用できるアップグレードを一覧します。各エントリーには installed_versionlatest_version、そしてパッケージ定義が changed かどうかが含まれます。

POST /packages/upgrades/dismiss 管理者

現在のアップグレード通知を見送ります。空の JSON オブジェクトを送ります。

POST /packages/manifest 認証済み

パッケージ定義の生の YAML を返します。reponameversion を送ります。ファイルの内容を Content-Type: text/x-yaml で返します。パッケージファイルが存在しない場合は 404 を返します。

GET /packages/featured 認証済み

すべてのリポジトリにまたがって、注目パッケージを一覧します。

POST /packages/last-responses 認証済み

パッケージについてキャッシュされた last の回答を取得します。reponame を送ります。再インストール時に再利用するために、以前の アンインストール時に保存された回答を返します。

POST /packages/clear-last-responses 管理者

パッケージについてキャッシュされた last の回答のファイルを削除します。reponame を送ります。

POST /packages/rebuild-git 管理者

インストール済みパッケージの、git を元にしたボリュームの最新の変更を取得し、 依存するサービスを再起動します。reponameversion を送ります。再ビルドの前に、保存された回答に対して テンプレート変数が再評価されます。

systemd

GET /systemd/units 認証済み / Localhost

Town OS が管理する systemd のユニットを一覧します。各エントリーには、ユニット名、説明、 load/active/sub の状態、関連するパッケージの識別子と説明、失敗フラグが含まれます。 ページ送りのパラメーターに対応しています。

GET /systemd/units-tree 認証済み / Localhost

平坦な一覧と同じユニットを、依存関係のツリーにまとめて返します。ルートのパッケージが最上位に来て、 依存はその親の下へ順に入れ子になります。/storage/package-volumes と同じ形です。 各行には平坦なエンドポイントが返すのと同じ状態のデータが入っているので、 クライアントが情報を補うために二度目のリクエストを送る必要はありません。

POST /systemd/status 管理者

systemd のユニットを操作します。name(ユニット名)と actionstartstoprestartenabledisable)を送ります。

POST /systemd/status/tree 管理者

一つのパッケージとその依存ツリー全体に対して、依存関係の順に同じ操作を一度の呼び出しで適用します。 ここでも enabledisable は拒否されます。理由は /systemd/status と同じで、enable を連鎖させると、親を通して既にリンクされている 依存を二重に有効化してしまうからです。

GET /systemd/logs 管理者 / Localhost

Server-Sent Events を使って、ユニットのジャーナルエントリーをリアルタイムに配信します。 unit のクエリパラメーターを渡します。空または __system__ の場合は システム全体のログを返します。各 SSE イベントには、MessagePriorityRealtimeTimestampSystemdUnit などの フィールドを持つ JSON 形式のジャーナルエントリーが含まれます。

GET /systemd/logs/tail 管理者 / Localhost

カーソル方式のページ送りと絞り込みで、ジャーナルエントリーを 1 ページ分取得します。

パラメーター説明
unitstringsystemd のユニット名。空または __system__ でシステム全体のログ。
linesint返すエントリー数(既定は 100)。
beforestringカーソル。この位置より前のエントリーを返します。
afterstringカーソル。この位置より後のエントリーを返します。
grepstringメッセージ本文に対する、大文字小文字を区別しない部分一致の絞り込み。
sinceintUnix タイムスタンプ。この時刻以降のエントリーを返します。
untilintUnix タイムスタンプ。この時刻で収集を打ち切ります。
priorityintsyslog の重大度による絞り込み(0 は絞り込みなし)。

以降のページ送りのために、entriescursor(最初のエントリー)、 end_cursor(最後のエントリー)を返します。

GET /systemd/logs/tree 管理者 / Localhost

/systemd/logs のツリー版です。一つのパッケージと、その下にあるすべてのユニットの ジャーナルを、時系列に混ぜて一本の Server-Sent Events ストリームで流します。インストールの記録が ない未知のルートであっても、404 ではなくエントリーのない開いたストリームが返るので、 ジャーナルビューアーは単一のユニットでもツリー全体でも同じように動きます。

GET /systemd/logs/tree/tail 管理者 / Localhost

混ぜ合わせたツリーのジャーナルをページ送りで取得する形式で、 /systemd/logs/tail と同じカーソル・フィルター・期間のパラメーターを受け取ります。

設定

GET /settings 管理者

すべての設定をキーと値のオブジェクトとして取得します。

POST /settings/get 管理者

設定を 1 件取得します。リクエストボディ: {"key": "default_quota"}keyvalue を返します。

POST /settings/set 管理者

設定の値を変更します。リクエストボディ: {"key": "default_quota", "value": "107374182400"}

既定の設定

キー既定値説明
default_quota53687091200(50 GB)新しいファイルシステムの既定のクォータ。
max_archive_size1073741824(1 GB)アーカイブのアップロードの最大サイズ。
archive_unpack_timeout600(秒)アーカイブの展開にかけられる最大時間。
localeen-US国際化のためのシステム全体のロケール。
proton_imagequay.io/town/proton:latestProton/Wine のランナーのコンテナーイメージ。
dns_tldhomeローカルの DNS 解決に使うトップレベルドメイン。

監査ログ

POST /audit/log 管理者

監査ログのエントリーを一覧します。リクエストボディのフィールドはすべて任意です。

フィールド説明
before_idintキーセット方式のページ送り。この ID より小さいエントリーを返します。
accountstringアカウントのユーザー名で絞り込みます。
sort_bystring並べ替えに使うフィールド。
sort_orderstringasc または desc
limitint1 ページあたりの件数。
offsetintページ送りのオフセット。
searchstring検索による絞り込み。

各監査エントリーには idaccountactionpathdetailsuccesserrorcreated_at が含まれます。監査対象の操作には、認証、アカウントの 作成・更新・無効化、セッションの失効、パッケージのインストール・アンインストール・ 無効化・有効化、ファイルシステムの作成・変更・削除、リポジトリの追加・削除・移動・更新、 アーカイブのアップロード・ダウンロード、設定の更新、アップグレードの見送り、 ボリュームの削除があります。

ページ

3 種類のコンテンツソース(アーカイブのアップロード、コンテナーイメージ、git リポジトリ)に 対応した静的サイトのホスティングです。利用者がドメインを割り当てると、システムが Caddy のコンテナーを通じてコンテンツを配信します。変更を伴うエンドポイントはすべて 管理者としての認証が必要で、一覧のエンドポイントは通常の認証で利用できます。

GET /pages 認証済み

すべてのページを、並べ替え、検索、ページ送りとともに一覧します。名前、リポジトリの URL、 ブランチ、ドメイン、ソースの種類、状態、タイムスタンプで並べ替えられます。

POST /pages/create 管理者

新しいページを作成します。名前、ソースの種類(archivecontainer_imagegit)、リポジトリの URL、ブランチ、ドメイン、 コンテナーイメージ、イメージ内のディレクトリを受け付けます。ソースの種類の既定値は archive です。git とコンテナーイメージのページは非同期に プロビジョニングされます。

POST /pages/upload 管理者

アーカイブ形式のページ向けに、コンテンツの tar アーカイブをアップロードします。 namearchive のファイルを含むマルチパートフォームを 受け付けます。ソースの種類が archive のページでのみ有効で、それ以外の 種類では 400 を返します。

POST /pages/update 管理者

ページのリポジトリ URL、ブランチ、ドメイン、ソースの種類、コンテナーイメージ、 イメージ内のディレクトリを部分的に更新します。指定したフィールドだけが変更されます。

POST /pages/remove 管理者

データベースからページを削除し、webroot のシンボリックリンクを外して、btrfs の サブボリュームを削除します。

POST /pages/rebuild 管理者

ページのコンテンツをソースから再ビルドします。git のページは最新の変更を取得し、 コンテナーイメージのページはイメージから取り出し直します。アーカイブのページは 400 を返します(代わりに /pages/upload で再アップロードしてください)。

ネットワーク

ネットワークとは、名前を持つ WireGuard オーバーレイと DNS の TLD を 組み合わせたものです。パッケージはネットワークにインストールされ、ピアはそこに参加し、 誰が何を解決できるかを分けるのが TLD です。ネットワーク名は DNS ラベルとして安全な形式で、 32 文字までに制限されています。WireGuard のインターフェース接尾辞と systemd の ユニット名にそのまま使い回されるからです。

home ネットワークは常に存在します。起動時に作られるのではなく、データベースそのものと 一緒に植え付けられます。そして三つの点で特別です。削除できず、二度目を作ることも できません。DNS 専用です(WireGuard のインターフェースもサブネットもピアも ありません)。そしてピアの登録は 400 で拒否されます。すべてのアカウントは home ネットワークに属しているので、ここで登録を受け付ければ、所属しているというだけで トンネルへの入口になってしまい、しかも保存されたピアは存在しないトンネルを記述することになります。

ネットワークを無効にすると止まるのは伝送路だけです。WireGuard のインターフェースが 立ち上がらなくなるのでリモートからの接続は切れますが、ローカルの DNS 解決とコンテナー自体は 動き続けます。

GET /networks 認証済み

ネットワークを一覧します。各エントリーには、名前、TLD、サブネット、オーバーレイ上での この機器自身のアドレス、公開鍵、待ち受けポート、有効フラグが入ります。秘密鍵が シリアライズされることはありません。

POST /networks/create 管理者

ネットワークを作成します。サブネットは、機器の識別情報のシードとネットワーク名から決定的に 導かれ、家庭用ルーターが配りがちな範囲を避けるために 10.64.0.0/10 から取られます。 機器の識別情報を鍵にしているので、ピアを受け入れる Town OS の機器が 2 台あっても別々の サブネットを選び、両方に参加する端末が衝突を見ることはありません。home を作ろうと すると、TLD の衝突チェックによって 409 が返ります。

POST /networks/remove 管理者

ネットワークを削除します。home ネットワークは拒否されます。

POST /networks/enable 管理者

そのネットワークの WireGuard の伝送路を立ち上げます。

POST /networks/disable 管理者

DNS とコンテナーを動かしたまま、伝送路だけを止めます。

ピア

GET /networks/peers 認証済み

あるネットワークに登録されているピアを一覧します。

GET /networks/peers/connected 管理者

登録されているだけでなく、実際に今つながっているピアを一覧します。

POST /networks/peers/add グラント

ピアを登録します。管理者でない利用者を通すのは wireguard のグラントで、ネットワークごとの 範囲と各ピアの所有関係はハンドラーが確認します。home ネットワークは DNS 専用なので 400 が返ります。

POST /networks/peers/refresh グラント

ピアの登録を TTL が切れる前に更新します。登録には期限があり、期限切れになったものは 回収する仕組みが取り除きます。

POST /networks/peers/remove 管理者

ピアをネットワークから取り除きます。

ローカル CA

GET /tls/ca.crt 公開

この機器のローカル認証局を PEM 形式でダウンロードします。Town OS はパッケージの名前に対して 自前の証明書を発行するので、この証明書を信頼することが、それらの名前をブラウザーで警告なしに 使えるようにする鍵になります。公開されているのは意図的です。CA 証明書は配布するためのもので あり、クライアントは認証に使える資格情報を持つより前にこれを必要とするからです。

オブジェクトストレージ

Town OS は gfeh によってオブジェクトストレージを提供します。 パーティションとは、一つの btrfs サブボリューム、一つの gfehd プロセス、一つの管理ソケット、そして専用の利用者群のことです。Town OS の ネットワークごとにちょうど一つ存在するので、オブジェクトストレージの名前空間は DNS や WireGuard と同じ境界で分かれます。office パーティションのプリンシパル、グラント、 公開は、home では何の意味も持ちません。

各パーティションは固定のコンテナーポートで四つの HTTP ビューを提供します。S3 が 9000、 HTTP が 9001、ドライブが 9002、IPFS が 9003 です。そしてホストのポートは一切 公開しません。固定ポートが安全なのはまさにそのためで、各パーティションは自分の ネットワーク名前空間を持ち、ingress はパッケージに到達するのと同じようにコンテナー名で 到達します。ですから 9000 で S3 を提供するパーティションが二つあっても衝突しません。

パーティション

この四つのルートが /storage/* とは別に存在するのは、/storage/create が 送られてきた名前を無条件に user/<名前> へ書き換えてしまい、 gfeh/ プレフィックスの下にボリュームを作れないからです。これらのワイヤー形式は gfeh のクライアントが解釈する公開された契約であって、内部の実装の詳細ではありません。

重要な点が二つあります。プレフィックスは非対称です。リクエストは素の名前を運び、 レスポンスは gfeh/<名前> を運びます。プレフィックスは Town OS の名前空間の 産物であって、パーティションの識別子の一部ではないからです。そして一覧はページ送りの 封筒ではなく、素の JSON 配列を返します。この API のほかのどの一覧エンドポイントとも 違う点で、gfeh のクライアントは素のリストを直接デシリアライズするため、ページ送りの包みでは デコードに失敗します。

ルート権限リクエストレスポンス
POST /gfeh/partitions/create管理者name(プレフィックスなし)、quotaFilesystem、名前は gfeh/<n>
POST /gfeh/partitions/modify管理者namequotaFilesystem
POST /gfeh/partitions/remove管理者name200、本文なし
POST /gfeh/partitions認証済み本文なしFilesystem の素の配列

クライアントが分岐すべきステータスコードは次のとおりです。409 は既に存在 (gfeh のプロビジョニングは「作成または容量変更」であり、この二つをこのステータスで見分けます)、 404 は存在しない、400 は名前が不正、403 は 管理者ではない。パスの区切り文字を含む名前はここで拒否されます。gfehd も自分の 境界で拒否するからで、「正当なパーティション名とは何か」で食い違えば、 ../user/something のような名前がオブジェクトストレージのルートの外にある ボリュームを指せてしまいます。

パーティションの作成は管理者専用で、グラントでは到達できません。 権限ツリーの根であり、クォータ付きの btrfs サブボリュームを確保するものなので、 グラントを持つアカウントはハンドラーが動くより前に拒否されます。

閲覧

GET /gfeh 認証済み

オブジェクトストレージの全体像です。どのパーティションが存在し、それぞれどのような状態かが分かります。

プリンシパル

パーティションの利用者です。作成には名前・親・上限を渡しますが、パスワードは 渡しません。UI が一度もパスワードを尋ねないのはそのためです。上限は gfeh の投影規則に 従い、Town OS の管理者なら all、それ以外は読み書きになります。

GET /gfeh/principals 認証済み

パーティション内のプリンシパルを一覧します。

POST /gfeh/principals/add グラント

親の下にプリンシパルを、上限を添えて作成します。

POST /gfeh/principals/remove グラント

プリンシパルを削除します。

グラント

ACL のことです。gfehdグラントをプリンシパルの上限まで切り詰めます。 ですからクライアントは、送った権限ではなく返ってきた権限を表示すべきです。 グラントが狭められたことを管理者が見て取れなければならないからです。

GET /gfeh/grants 認証済み

グラントを一覧します。一つのプリンシパルに絞ることもできます。

POST /gfeh/grants/add グラント

プリンシパルにアクセス権を与えます。レスポンスには実際に保存された権限が入ります。

POST /gfeh/grants/revoke グラント

id を指定してグラントを取り消します。

公開

/f/<token> で提供される、公開されたファイルのリンクです。

GET /gfeh/exposures 認証済み

パーティション内で公開されているリンクを一覧します。

POST /gfeh/exposures/withdraw グラント

トークンを指定して公開リンクを取り下げ、その URL が解決しないようにします。

DNS

rolodex-dns コンテナーを基盤とする、統合されたローカル DNS リゾルバーです。 インストール済みパッケージのゾーンファイルとレコードを管理し、gRPC の Unix ソケット インターフェースを通じてローカルの名前解決を提供します。

GET /dns/status 認証済み

有効フラグ、稼働状態、TLD、レコード数を含む DNS の状態を返します。

GET /dns/records 認証済み

すべての DNS レコードを一覧します。

POST /dns/records/add 管理者

DNS レコードを追加します。名前、レコードの種類、値、TTL を受け付けます。

POST /dns/records/remove 管理者

名前と種類を指定して DNS レコードを削除します。

GET /dns/tld 認証済み

現在のトップレベルドメインの設定を取得します。

POST /dns/tld 管理者

TLD を設定します。既存の TLD を変更し、インストール済みのパッケージをすべて登録し直します。

POST /dns/setup 管理者

DNS サーバーを初期化または再起動し、インストール済みのパッケージをすべて登録します。

ブロックリスト

互いに独立した二つのリストがあります。DNSBL は購読型で、rolodex が取得して 適用する上流のブロックリストです。これには許可リストが付いていて、上流のリストが何と言おうと 解決させたい名前を除外できます。ローカルのブロックリスト(RBL)は この機器自身のリストで、一件ずつ編集します。

GET /dns/dnsbl 認証済み

DNSBL の構成を取得します。どの上流ブロックリストを購読していて、どのように適用しているかが分かります。

POST /dns/dnsbl 管理者

DNSBL の構成を置き換えます。

GET /dns/dnsbl/allowlist 認証済み

購読中のブロックリストから除外されている名前を一覧します。

POST /dns/dnsbl/allowlist/add 管理者

購読中のブロックリストから、ある名前を除外します。

POST /dns/dnsbl/allowlist/remove 管理者

許可リストの項目を取り除き、購読中のブロックリストがその名前に再び適用されるようにします。

GET /dns/rbl/local 認証済み

この機器自身のブロックリストの項目を一覧します。

POST /dns/rbl/local/add 管理者

ローカルのブロックリストに名前を追加します。

POST /dns/rbl/local/remove 管理者

ローカルのブロックリストから名前を取り除きます。

サービスごとの DNS 公開

GET /dns/services 認証済み

インストール済みのサービスを、それぞれが DNS に名前を公開しているかどうかとあわせて一覧します。

POST /dns/services/set 管理者

あるサービスの DNS 公開を切り替えます。パッケージが、ネットワーク上の名前を主張せずに 動けるようにするためのものです。

モニタリング

システム監視のために統合された Prometheus、Node Exporter、Grafana のスタックです。 スタックは Restart=always を設定した、systemd 管理下の podman コンテナーとして動作します。

GET /monitoring/status 認証済み

監視サービスごとにコンテナーの状態(名前、イメージ、稼働状態、ポート)を返します。 監視が構成されていない場合は {"status": "disabled"} を返します。

ダッシュボードのデータへの到達方法

システムコントローラーを通るリバースプロキシは存在しません。 監視データは専用のポート 5308 で提供され、ブラウザーはそのポートと直接やり取りします。 コントローラー自身のポート(5309)が担うのは /monitoring/status だけです。 5308 で何が待ち受けるかは、構成されたバックエンドによって決まります。

  • uPlot モード(既定)—— socat のフォワーダーが Prometheus の HTTP API を 5308 に出し、UI は /api/v1/query_range を直接問い合わせて、自分でグラフを描きます。
  • Grafana モード—— podman のポートマッピングによって Grafana が 5308 で直接待ち受け、 UI はそれを iframe に埋め込みます。

TOWN_OS_MONITORING_PORT はダッシュボードのポートを移動させ、 TOWN_OS_PROMETHEUS_PORTTOWN_OS_NODE_EXPORTER_PORT は 二つのループバックのポートに対して同じ働きをします。

システムサービス

システムサービスは、systemd が管理する基盤コンテナーです(利用者がインストールした パッケージのサービスとは区別されます)。ユニット名には town-os-system-- の プレフィックスが付きます。

GET /system-services 公開 / 認証済み

システムサービスを、ユニットの現在の状態とともに一覧します。localhost からは認証なしで アクセスできます。各エントリーには、キー、表示名、イメージ、ポート、systemd の ユニットの状態のフィールドが含まれます。

POST /system-services/status 管理者

システムサービスを操作します。keyactionstartstoprestart)を受け付けます。

POST /system-services/refresh 管理者

システムサービスのユニットファイルと状態を再読み込みします。

ロケール

システムの国際化に関するロケールの情報です。

GET /locales 認証済み

現在のロケール、翻訳が用意されているロケールの一覧、主要な言語(それぞれの文字での 名称つき)、拡張ロケールを返します。BCP 47 のロケールコードを使います。

VM イメージ

VM パッケージが使う、キャッシュされた VM のディスクイメージの管理です。リモートの イメージはダウンロードされ、qemu-img convert で raw 形式に変換されます。 変換後のイメージは vm-images のサブボリュームにキャッシュされます。

GET /vm-images 認証済み

キャッシュされた VM のディスクイメージを一覧します。各イメージの名前とファイルサイズを返します。

POST /vm-images/upload 管理者

URL から VM のイメージをダウンロードし、raw 形式に変換します。URL と任意の名前を 受け付けます。名前の既定値は、URL のファイル名に .raw の拡張子を 付けたものです。ダウンロードのタイムアウトは 30 分です。

POST /vm-images/delete 管理者

名前を指定して、キャッシュされた VM のイメージを削除します。

オブジェクトストレージ管理 API(gfeh)

ここまではすべて Town OS の API で、アプリケーションが普段使うべきものはそちらです。その下で、 各 gfehd パーティションは独自の管理面を持っています。JSON over HTTP ですが、 その Unix ソケットの上だけで提供され、ポートで待ち受けることはありません。

この面にはトークンも認証もありません。ソケットに対するファイルシステムの パーミッションそのものがアクセス制御であり、そこへ到達できる時点で、その機器の root であることを意味します。ソケットが btrfs のボリュームの上にあるのは、 gfehd のコンテナーとシステムコントローラーのコンテナーの双方から見える 唯一のファイルシステムがそこだからです。

呼び出しメソッドとパス用途
HealthGET /v1/health生存確認であり、レディネスプローブでもあります。
NamesGET /v1/namesこのパーティションが公開したい名前。
ListPrincipalsGET /v1/principalsパーティションの利用者のフォレスト。
CreatePrincipalPOST /v1/principalsnameparentceiling を受け取ります。パスワードはありません。
DeletePrincipalDELETE /v1/principals/<name>プリンシパルを取り除きます。
ListGrantsGET /v1/grants?principal=ACL。一つのプリンシパルに絞ることもできます。
CreateGrantPOST /v1/grantsアクセス権を与えます。プリンシパルの上限まで切り詰められます。
RevokeGrantDELETE /v1/grants/<id>グラントを取り消します。
ListExposuresGET /v1/exposures公開された /f/<token> のリンク。
WithdrawExposureDELETE /v1/exposures/<token>公開リンクの提供をやめます。

gfehd は内部のエラーを HTTP のステータスコード(404、409、400)に対応付け、 Go のクライアントがそれをセンチネルエラーへ戻します。おかげで errors.Is が ソケットの境界をまたいでも機能します。

<network> という名前のネットワークについて、パーティションのファイルの置き場所は次のとおりです。

対象場所
パーティションのデータ<btrfsBase>/gfeh/<network>/data/<network> にマウント
構成<btrfsBase>/gfeh-control/<network>/gfehd.yaml
管理ソケット<btrfsBase>/gfeh-control/<network>/run/admin.sock
ユニットtown-os-system--gfeh-<network>.service

DNS gRPC API(rolodex)

上にある /dns/* のエンドポイントは、Town OS から見た DNS です。rolodex 自体は gRPC で管理され、Unix ソケット(既定では /var/run/rolodex-dns.sock)に、必要なら TCP にも公開されます。初期状態では ソケットが唯一の管理経路で、grpc.tcp_bind は空です。

サービスは rolodex_dns.RolodexDnsService の一つだけで、74 のメソッドを持ちます。 パスはすべて /rolodex_dns.RolodexDnsService/<メソッド名> です。メッセージの 完全な定義は rolodex-dns リポジトリーの proto/rolodex_dns.proto にあります。 以下のまとまりは、それらのメソッドが何を扱うのかを示したものです。

レコードと解決

メソッド用途
AddRecordローカルのデータベースに DNS レコードを追加します。
RemoveRecordローカルのデータベースからレコードを取り除きます。
ListRecords任意のフィルターでローカルのデータベースを問い合わせます。
SetForwarders上位のフォワーダーを構成します。
SetResolutionMode / GetResolutionMode解決モードを実行時に変更し、読み取ります。
GetSearchDomainsあるクライアント IP に対する検索ドメイン。
FlushCacheDNS とブロックリストのキャッシュを消します。

権威ゾーン

メソッド用途
AddAuthoritativeZoneゾーンを権威ゾーンとして宣言します。
RemoveAuthoritativeZoneゾーンを権威ゾーンの一覧から外します。
ListAuthoritativeZones権威ゾーンを一覧します。

ネットワークスコープ

スコープは rolodex が「誰が何を解決できるか」を分ける仕組みで、Town OS のネットワークが 対応付けられる先でもあります。IP とスコープの結び付きには TTL があり、更新が必要です。

メソッド用途
CreateNetworkScope / DeleteNetworkScope / ListNetworkScopesスコープを管理します。削除すると、そのレコードと結び付きも一緒に消えます。
JoinNetwork / LeaveNetworkクライアント IP をスコープに結び付け、あるいは解除します。
GetNetworkAssociationsIP とスコープの結び付きを読み取ります。
AddScopedRecord / RemoveScopedRecord / ListScopedRecordsあるスコープの中だけに存在するレコード。

スコープの TLD

ネットワークごとに所有され、ネットワーク間で分割されるゾーンです。

メソッド用途
AddScopeTld / RemoveScopeTld / ListScopeTlds全体で一意な TLD を、あるスコープの所有として登録します。
SetScopeTldForwarders / ListScopeTldForwardersスコープの TLD に対するピアのフォワーダー。
ListScopeTldListenersスコープの TLD に紐づく ingress の DNS リスナー。

ブロックリスト

メソッド用途
SetDnsblConfig / GetDnsblConfig購読型のドメインブロックリストの構成。
AddDnsblAllowlistEntryある名前とそのサブドメインを、名前によるブロック判定から除外します。
RemoveDnsblAllowlistEntry / ListDnsblAllowlistEntries許可リストを管理します。
AddLocalBlocklistEntry / RemoveLocalBlocklistEntry / ListLocalBlocklistEntriesこの機器自身のブロックリスト。

暗号化されたトランスポート

どのトランスポートにも、設定と取得の組があります。DoH は HTTP/2 を提供し、 enable_h3 が有効なときは同じアドレス・ポート・証明書で HTTP/3 も提供します。

メソッド用途
SetDotConfig / GetDotConfigDNS over TLS。
SetDohConfig / GetDohConfigDNS over HTTPS。HTTP/3 を含みます。
SetDoqConfig / GetDoqConfigDNS over QUIC。
SetProxyConfig / GetProxyConfigHTTP プロキシーの構成。

DNSSEC・DANE・ACME

メソッド用途
GenerateDnssecKey / ListDnssecKeys / DeleteDnssecKeyゾーンごとの DNSSEC の鍵。
GetDsRecordsゾーンの DS レコード。
SignZoneゾーンをその DNSSEC の鍵で署名します。
GenerateTlsaRecord / ListTlsaRecords証明書から生成する TLSA レコード。
GenerateDaneRootCaDANE 用のルート CA 証明書を生成します。
EnsureZoneCaゾーンに CA があることを確かめます。
RequestAcmeCert / GetAcmeStatusACME DNS-01 で証明書を要求し、その状態を読み取ります。
CreateEabCredential / RemoveEabCredentialゾーンに限定した External Account Binding(kid と HMAC)を発行します。ACME クライアントの newAccount で使います。
ListAcmeAccounts / ListAcmeCertificates登録済みの ACME アカウントと発行済みの証明書。

DHCP

メソッド用途
AddDhcpPool / RemoveDhcpPool / ListDhcpPoolsスコープ内で割り当てるアドレスプール。
ListDhcpLeases / DeleteDhcpLeaseリース。削除は MAC アドレスで行います。
SetDhcpCertOption / RemoveDhcpCertOption / ListDhcpCertOptionsスコープに対し DHCP でクライアントへ配る証明書。

診断と調整

メソッド用途
GetCacheStats / FlushDnsCacheキャッシュの統計と、応答キャッシュの消去。
GetQueryLatencyStats上位への問い合わせのレイテンシー。
SetTtlDriftConfig / GetTtlDriftConfigTTL ドリフトの構成。
SetTrackedTlds / ListTrackedTldsTLD 別メトリクスの背後にある追跡対象 TLD の一覧。保存されたものと実効のもの。
SetDns64Config / GetDns64ConfigDNS64 の構成。

クライアントライブラリ

Town OS には、API を完全に網羅した Go と JavaScript のクライアントライブラリが 同梱されています。どちらのクライアントも、200 以外のレスポンスに対して RFC 9457 の problem detail を使った型付きのエラーを送出します。

Go クライアント

Go クライアントは src/svc/systemcontroller/client.go にあり、 Client インターフェースを実装しています。Unix ソケットと HTTP の どちらの接続にも対応します。

// Connect via Unix domain socket (production)
client := systemcontroller.InitClient("/run/town-os/systemcontroller.sock")

// Connect via HTTP (development / testing)
client := systemcontroller.FromClient(http.DefaultClient, "http://localhost:5309")

認証後は client.Token を設定してください。すべてのメソッドは、 第 1 引数に context.Context を取ります。

ストレージ

メソッド説明
CreateFilesystem(ctx, fs)新しい btrfs のサブボリュームを作成します。
ModifyFilesystem(ctx, name, fs)ファイルシステムの名前変更やサイズ変更を行います。
RemoveFilesystem(ctx, name)名前を指定してファイルシステムを削除します。
ListFilesystems(ctx, prefix, state, params)名前の前方一致と状態("user""installed""uninstalled")で絞り込んだページ送り可能な一覧。

リポジトリ

メソッド説明
AddRepository(ctx, name, rawURL, username, password)任意の認証情報とともにパッケージリポジトリを登録します。
RemoveRepository(ctx, name)名前を指定してリポジトリを削除します。
MoveRepository(ctx, name, position)優先度を変更します(0 が最上位)。
RefreshRepositories(ctx)すべてのメタデータを更新します。エラーのマップを返します。
ListRepositories(ctx, params)リポジトリのページ送り可能な一覧。

パッケージ

メソッド説明
ListPackages(ctx, params)利用できるパッケージのページ送り可能な一覧。
ListPackagesByRepo(ctx, params)リポジトリごとにまとめたパッケージ。
ListPackageVersions(ctx, name)パッケージの利用できるバージョン。
GetPackageQuestions(ctx, name)名前を指定して設定用の質問を取得します。
GetPackageQuestionsByIdentity(ctx, repo, name, version)特定のバージョンの質問。
ListChildren(ctx, repo, name)子パッケージの名前。
InstallPreview(ctx, repo, name, version)インストールせずにボリュームとポートをプレビューします。
InstallPackage(ctx, name, version, responses, reuseVolumes, importFromVersion, skipResponseReuse)パッケージをインストールします。name は "repo/package" の形式です。
UninstallPackage(ctx, repo, name, version, purgeVolumes)インストール済みのパッケージを削除します。
DisablePackage(ctx, repo, name)アンインストールせずにサービスを停止します。
EnablePackage(ctx, repo, name)無効にしたパッケージを再び有効にします。
PurgeVolumes(ctx, repo, name)パッケージのデータボリュームをすべて削除します。
ListUninstalledVolumes(ctx, repo, name)残っているボリュームがあるか確認します。
PurgeUninstalledVolumes(ctx, repo, name)残っているボリュームを削除します。
ListInstalled(ctx, params)インストール済みパッケージを "repo/name@version" として返します。
GetResponses(ctx, repo, name, version)保存された設定の回答。
GetInstalledInfo(ctx, repo, name, version)質問、回答、ノートを含む詳細情報。

systemd

メソッド説明
ListUnits(ctx, params)systemd のユニットのページ送り可能な一覧。
SetUnitStatus(ctx, name, action)"start""stop""restart" を適用します。
LogReplay(ctx, name)SSE でジャーナルエントリーを配信します。チャネルを返します。
LogTail(ctx, params)カーソル方式のページ送り、grep、期間、優先度で絞り込んだジャーナルエントリー 1 ページ分。

アカウント

メソッド説明
Authenticate(ctx, username, password)セッショントークンとアカウントを返します。
CreateAccount(ctx, username, password, email, phone, realName, admin)ユーザーを作成します。パスワードは 8 文字以上。
GetAccount(ctx, username)ユーザー名でアカウントを取得します。
UpdateAccount(ctx, username, fields)アカウントのフィールド(password、email、phone、real_name、admin)を変更します。
ListAccounts(ctx, params)アカウントのページ送り可能な一覧。
DisableAccount(ctx, username)認証を拒否するようにします。
EnableAccount(ctx, username)無効にしたアカウントを再び有効にします。
ListSessions(ctx, token)そのトークンのユーザーの有効なセッション。
SessionUsername(ctx, token)セッショントークンに対応するユーザー名。
RevokeSession(ctx, sessionID)セッションを無効にします。

監査・設定・アップグレード

メソッド説明
ListAuditLog(ctx, opts, token)絞り込みつきのページ送り可能な監査ログ。
GetSettings(ctx)すべての設定をキーと値のマップとして返します。
GetSetting(ctx, key)キーを指定して設定を 1 件取得します。
SetSetting(ctx, key, value)設定を更新します。
ListUpgrades(ctx)新しいバージョンが利用できるパッケージ。
DismissUpgrades(ctx)保留中のアップグレードを見送り済みにします。

アーカイブ

メソッド説明
UploadArchive(ctx, subvolume, archiveReader, filename, subpath, stopService)アーカイブをアップロードしてサブボリュームへ展開します。形式は tar.gz、tar.bz2、tar.xz。
DownloadArchive(ctx, subvolume, paths, stopService, format)サブボリュームの内容のアーカイブを作成します。io.ReadCloser を返します。

ヘルス

メソッド説明
Ping(ctx)サービスの状態と各種の件数のまとめ。

JavaScript クライアント

JavaScript クライアントは ui/src/api/ にあり、Town OS のダッシュボード UI が 使っています。SystemControllerClient クラスにミックスインを重ねる モジュラーな構成です。200 以外のレスポンスでは、解析済みの RFC 9457 の problem detail を 持つ ApiError が送出されます。

import SystemControllerClient from './api/client.js';

const client = new SystemControllerClient('http://localhost:5309');

// After authentication
const result = await client.authenticate('admin', 'password');
client.setToken(result.token);

ストレージ

メソッド説明
createFilesystem(fs)新しい btrfs のサブボリュームを作成します。
modifyFilesystem(name, fs)ファイルシステムの名前変更やサイズ変更を行います。
removeFilesystem(name)名前を指定してファイルシステムを削除します。
listFilesystems(prefix, sortBy, sortOrder, state, limit, offset, search)絞り込みつきのページ送り可能な一覧。

リポジトリ

メソッド説明
addRepository(name, url, username?, password?)任意の認証情報とともにリポジトリを登録します。
removeRepository(name)名前を指定してリポジトリを削除します。
moveRepository(name, position)優先度を変更します(0 が最上位)。
refreshRepositories()すべてのメタデータを更新します。エラーのマップか null を返します。
listRepositories(sortBy, sortOrder, limit, offset, search)ページ送り可能な一覧。

パッケージ

メソッド説明
listPackages(sortBy, sortOrder, limit, offset, search)利用できるパッケージのページ送り可能な一覧。
listPackagesByRepo(search)リポジトリごとにまとめたパッケージ。
listPackageVersions(name)パッケージの利用できるバージョン。
getPackageQuestions(name)名前を指定して設定用の質問を取得します。
getPackageQuestionsByIdentity(repo, name, version)特定のバージョンの質問。
installPreview(repo, name, version)インストールせずにボリュームとポートをプレビューします。
installPackage(repo, name, version, responses, reuseVolumes?, importFromVersion?)設定の回答とともにパッケージをインストールします。
uninstallPackage(repo, name, version, purgeVolumes?)インストール済みのパッケージを削除します。
disablePackage(repo, name)アンインストールせずにサービスを停止します。
enablePackage(repo, name)無効にしたパッケージを再び有効にします。
purgeVolumes(repo, name)パッケージのデータボリュームをすべて削除します。
listUninstalledVolumes(repo, name)残っているボリュームがあるか確認します。
purgeUninstalledVolumes(repo, name)残っているボリュームを削除します。
listInstalled(sortBy, sortOrder, limit, offset, search)インストール済みパッケージを "repo/name@version" として返します。
getResponses(repo, name, version)保存された設定の回答。
getInstalledInfo(repo, name, version)質問、回答、ノートを含む詳細情報。

systemd

メソッド説明
listUnits(sortBy, sortOrder, limit, offset, search)systemd のユニットのページ送り可能な一覧。
setUnitStatus(name, action)"start""stop""restart" を適用します。
logReplay(unit)SSE でジャーナルエントリーを配信します。AsyncGenerator を返します。
logTail(unit, lines?, before?, after?, grep?, since?, until?, priority?)カーソル方式のページ送り、grep、期間、優先度で絞り込んだジャーナルエントリー 1 ページ分。

アカウント

メソッド説明
authenticate(username, password)セッショントークンとアカウントを返します。
createAccount(username, password, email, phone, realName, admin)ユーザーを作成します。パスワードは 8 文字以上。
getAccount(username)ユーザー名でアカウントを取得します。
updateAccount(username, fields)アカウントのフィールドを変更します。
listAccounts(sortBy, sortOrder, limit, offset, search)アカウントのページ送り可能な一覧。
disableAccount(username)認証を拒否するようにします。
enableAccount(username)無効にしたアカウントを再び有効にします。
listSessions(token)そのトークンのユーザーの有効なセッション。
sessionUsername(token)セッショントークンに対応するユーザー名。
revokeSession(sessionID)セッションを無効にします。

監査・設定・アップグレード

メソッド説明
listAuditLog(opts)絞り込みつきのページ送り可能な監査ログ。
getSettings()すべての設定をキーと値のオブジェクトとして返します。
getSetting(key)キーを指定して設定を 1 件取得します。
setSetting(key, value)設定を更新します。
listUpgrades()新しいバージョンが利用できるパッケージ。
dismissUpgrades()保留中のアップグレードを見送り済みにします。

アーカイブ

メソッド説明
uploadArchive(subvolume, file, subpath?, stopService?)FormData でアーカイブをアップロードして展開します。{needs_restart, message} を返します。
downloadArchive(subvolume, paths?, stopService?, format?)サブボリュームのアーカイブをダウンロードします。ストリーミングのために生の Response を返します。

ヘルス

メソッド説明
ping()サービスの状態と各種の件数のまとめ。

開発リファレンス

Town OS のバックエンドはポート 5309 で動作し、Vite の開発サーバーはポート 5173 で動きます。 開発環境一式を起動するには make dev を使ってください。

主要なターゲット

ターゲット説明
make dev開発環境一式を起動します(バックエンド + Vite の開発サーバー)。
make dev-stop開発用バックエンドのコンテナーを停止して削除します。
make dev-logs稼働中の開発用コンテナー内で journalctl を追います。
make dev-cleanコンテナーを停止し、開発用の btrfs ボリュームを片付けます。

テスト用のターゲット

ターゲット説明
make testlint、Go のユニットテスト、JS のユニットテストを実行します。
make test-integration特権付きの Podman コンテナー内で Go の統合テストを実行します。
make test-ui-integrationバックエンドのコンテナーに対して Bun の UI 統合テストを実行します。
make test-fullすべてのテストスイートを順に実行します。
make auto-testファイルの変更を監視してテストを自動的に再実行します。

ビルド用のターゲット

ターゲット説明
make production-image本番用のコンテナーイメージをビルドします。
make test-imageテスト用のコンテナーイメージをビルドします。
make pull-imagesベースとなるコンテナーイメージを Docker Hub から取得します。

事前に必要なもの

  • Go 1.25 以降
  • Bun — JavaScript ランタイム
  • Podmansudo を使う rootful モード
  • btrfs-progsmkfs.btrfs
  • golangci-lint

リポジトリの認証情報を記した .env ファイルを作成します。

TOWN_OS_REPO_USERNAME=<username>
TOWN_OS_REPO_PASSWORD=<password>

必要なものを導入したら、ほかのターゲットを実行する前に make pull-images を 実行してください。