基本概念
Town OS はいくつかの中核となる考え方の上に成り立っています。これらの概念を理解すれば、 パッケージの定義から稼働中サービスの管理まで、全体がどのようにかみ合っているのかが つかめるようになります。
パッケージ
パッケージとは、git リポジトリから取得される、サービスを自己完結的に記述した YAML 定義です。
各パッケージには、ネットワークのポートマッピング、ストレージのボリューム、環境変数、
対話形式の質問など、そのサービスを動かすために必要な情報がすべて含まれます。パッケージは
コンテナー(既定)、QEMU ベースの仮想マシン、あるいは Valve の Proton 互換レイヤーを介した
Windows アプリケーションとして実行できます。ファイルテンプレート(Go の
text/template ファイル)はインストール時にボリュームへ展開でき、
動的な設定が可能です。パッケージは自らの機能を表すために supplies タグ
(http、database、cache など)を宣言します。
既定のリポジトリには、git ホスティング、ビデオ会議、メディア配信、チームチャット、
データベースなどを網羅した厳選パッケージが同梱されており、随時追加されています。
質問
パッケージをインストールすると、Town OS は「質問」と呼ばれる対話形式のプロンプトを表示することがあります。
入力した回答は、パッケージ定義全体にある @variable@ というテンプレートの
プレースホルダーに埋め込まれ、ホスト名、ポート、認証情報などの項目を設定します。各質問には
型付きのバリデーター(hostname、port、bytes、
volume、archive、duration、secret、
boolean、oauth、または自由入力のテキスト)と任意の既定値があるため、
設定の誤りはサービスが起動する前に検出されます。型は表示される入力欄も決めます。
boolean はチェックボックス、secret は伏せ字の入力欄、
oauth の質問は接続ボタンになり、提供元にサインインして返されたトークンを保持します。
いくつかの型は、空のままにすると値を自動生成します。ポートは 10000〜60000 の範囲から
ランダムに割り当てられ、ホスト名は package-name-4hex の形式で生成され、
シークレットは 64 文字の 16 進文字列になります。optional と指定された質問は
空欄のままでもかまいません。使っていない SMTP リレーは、当て推量で埋められるのではなく
未設定のままになります。
サービス
パッケージをインストールすると、それはサービス、つまり systemd ユニットが管理する 稼働中のコンテナーになります。Town OS では、開始・停止・再起動の操作、 Server-Sent Events によるログのリアルタイム配信、カーソル方式のジャーナルのページ送り、 サービスの有効化・無効化が行えます。サービスは互いに、そしてホストシステムからも隔離されています。
ネットワーク
Town OS には
rolodex
が含まれます。パッケージ用の権威ゾーンを管理し、上位への問い合わせを転送する DNS サーバーです。
各パッケージは自分のポートマッピングを宣言します。external ポートはホストに公開され、
internal ポートはコンテナー間でのみ利用できます。ポートの値は
@variable@ テンプレートに対応しているので、インストール時に利用者が選べます。
依存関係を宣言したパッケージはネットワークを共有するため、同じ依存ツリーにあるコンテナー同士は
直接通信できます。親パッケージは環境変数の中で
@dep_KEY_host@ や @dep_KEY_port_N@ といったテンプレート変数を使うか、
実行時の環境変数(TOWNOS_DEP_{KEY}_HOST と
TOWNOS_DEP_{KEY}_PORT_{port})を使って依存先を参照できます。UPnP による
ポート転送は自動的に処理されます。
ネットワーク
ネットワークとは、名前を持つ WireGuard オーバーレイと DNS の TLD を
組み合わせたものです。パッケージはネットワークにインストールされ、ピアはそこに参加し、
誰が何を解決できるかは TLD が決めます。home ネットワークは常に存在し、
削除できず、DNS 専用です。トンネルを持たず、ピアの登録も拒否されます。すべてのアカウントは
既にこのネットワークに属しているため、所属しているというだけでトンネルへの入口になっては
ならないからです。ほかのネットワークには WireGuard インターフェースと、この機器自身の
識別情報から導かれるサブネットが与えられるので、2 台の Town OS 機器に参加する端末が
衝突を起こすことはありません。ネットワークを無効にすると停止するのは伝送路だけです。
リモートからの接続は切れますが、ローカルの DNS とコンテナーはそのまま動き続けます。
Ingress
共有された一つの玄関です。単一の Caddy インスタンスが機器全体の :443 と
:80 を保持し、どのサービスに届くかは SNI と Host だけで選ばれます。
サービスごとのリスナーも bind ディレクティブもないので、LAN のクライアントと
オーバーレイのピアは同じソケットに届き、同じ証明書を受け取り、同じコンテナーへ
プロキシーされます。パッケージの名前は一つの文字列でありながら、同時に四通りに使われます。
A レコード、証明書の SAN、TLSA の所有者、そして ingress のバーチャルホストです。
TLS とローカル CA
Town OS は自前の認証局を動かし、パッケージが主張する名前に対して証明書を発行します。
そのため、公的な証明書もブラウザーの警告もなしに、サービスへ HTTPS で到達できます。
CA 証明書は /tls/ca.crt からダウンロードでき、一度これを信頼すれば、
すべてのローカルな名前が機能するようになります。証明書は起動時ではなくバックグラウンドで
更新され、TLD を変更すると、それに依存する名前が再発行されます。
オブジェクトストレージ
Town OS は gfeh によってオブジェクトストレージを提供します。 パーティションとは、専用のデーモンと専用の利用者群を持つ btrfs の サブボリュームであり、ネットワークごとにちょうど一つ存在します。したがって、あるネットワークでの 利用者・権限・公開リンクは、別のネットワークでは何の意味も持ちません。各パーティションは S3、素の HTTP、ドライブ風のブラウザー、IPFS という四つのビューを提供します。利用者は ツリー状に並ぶプリンシパルで、アクセス権はグラントとして 与えられ、常に付与先プリンシパルの上限まで切り詰められます。公開リンクは あとから取り下げられる公開です。ホストのポートを公開するパーティションは一つもなく、 ingress はコンテナー名でそれぞれに到達します。
ストレージ
データはすべて btrfs のサブボリューム上に保存され、パッケージごとに分離されます。各ボリュームには
コンテナー内のマウントポイント、設定可能なクォータ(512mb、2gb など)、
任意の uid/gid 所有者があります。ボリュームは archives 機能を
使ってコンテナーイメージからあらかじめ内容を展開したり、インストール時に空のボリュームへ
git リポジトリをクローンして初期データを用意したりできます。利用者が独立したボリュームを
自分で作ることも可能です。VM のディスクイメージは専用のサブボリュームにキャッシュされ、
以降のインストールで再利用されます。ある時点のバックアップとして btrfs のスナップショットも
利用できます。データはパッケージの再インストールやアップグレードをまたいで保持されるため、
サービスを更新してもファイルが失われることはありません。
リポジトリ
パッケージはリポジトリ単位で整理されます。リポジトリとは、バージョン管理された YAML 定義を収めた
packages/ ディレクトリを含む git リポジトリのことです。すべての Town OS 環境には
既定のリポジトリが含まれますが、誰でも独自のリポジトリを作成して共有できます。リポジトリには
順序があり、パッケージ名が衝突した場合は後のエントリーが先のものを上書きします。
featured.json ファイルを置くと、選んだパッケージを UI 上で目立たせられます。
テンプレートとノート
@variable@ テンプレートの仕組みが、質問への回答を環境変数、ポートマッピング、
ボリュームのクォータなどに結びつけます。@LOCAL_EXTERNAL_HOST@ や
@LOCAL_INTERNAL_HOST@ といった組み込み変数は常に利用できます。インストール後は
notes が接続 URL、認証情報、連絡先といった重要な情報を表示します。
url、phone、email については型の検証も行えます。
ページ
Town OS は静的ウェブサイトをホストできます。各ページのソースには 3 種類の方式があります。 tar アーカイブのアップロード、コンテナーイメージからのファイル抽出、git リポジトリのクローンです。 すべてのページは専用のドメインを持ち、Caddy 経由で配信されます。アーカイブ方式のページは 再アップロードで更新でき、git とコンテナーイメージ方式のページは必要に応じて再ビルドできます。
モニタリング
組み込みの可観測性スタックが、設定なしでそのまま動作します。Prometheus が指標を収集し、 Node Exporter がホストの統計情報(CPU、メモリ、ディスク、ネットワーク)を報告します。 モニタリングのバックエンドは 2 種類から選べます。軽量な組み込み UI(既定)か、 ダッシュボードが自動構成される Grafana です。スタック全体はシステムサービスとして動作し、 障害時には自動的に再起動します。
国際化
利用者に表示される文字列はすべて、BCP 47 のロケールコードをキーとするメッセージカタログを経由します。
主要な 21 言語がそれぞれの文字で表示され、国・地域別のコードは 87 種類以上が利用できます。
現時点で完全に翻訳されているのは英語(en-US)のみですが、
コミュニティによる翻訳を受け入れる基盤は整っています。
アカウントとセッション
Town OS は管理者アカウントと一般ユーザーアカウントに対応しています。パスワードは 8 文字以上が必要です。 認証には JWT トークンを使い、7 日間操作がなければ期限切れになります。セッションは一時的なもので、 署名鍵は再起動のたびに生成し直されるため、有効なセッションはすべて自動的に消去されます。
監査ログ
管理操作はすべて、アカウント名、操作内容、リクエストパス、詳細、成否フラグ、タイムスタンプとともに 記録されます。読み取り専用のエンドポイントは対象外です。監査ログはページ送り、 アカウントによる絞り込み、全文検索に対応しています。
設定
システム全体の構成は、UI 上のキーと値による設定で管理します。設定できる項目には、 既定のボリュームクォータ(50 GB)、アーカイブの最大アップロードサイズ(1 GB)、 アーカイブ展開のタイムアウト(600 秒)、ロケール、Proton ランナーのイメージ、 DNS のトップレベルドメインなどがあります。
パッケージのアップグレード
Town OS は、設定済みのリポジトリに新しいバージョンのパッケージが登場したことを自動的に検出します。 ダッシュボードのバッジには、保留中のアップグレード数が表示されます。適用したくないバージョンは 見送ることができます。見送りの記録は SHA256 ハッシュで管理されるため、 アップグレードの組み合わせが変わったときにだけ再び表示されます。
システムサービス
モニタリング、DNS、ウェブ UI といった基盤コンテナーは、利用者がインストールしたパッケージとは
別に管理されます。これらは専用の systemd プレフィックス(town-os-system--)を使い、
障害時には必ず再起動し、利用者が無効化することはできません。