コンテンツにスキップ
公式サイト →

まとめて読む

はじめに


ドキュメントガイド

このドキュメントは、Keelson を使ってアプリをデプロイ・運用するための情報をまとめたものです。

Keelson のサービス概要、料金、セキュリティについては 公式サイト を参照してください。

Keelson の対応ランタイムや制約は Keelson Deploy Spec に1ページでまとまっています。以下の URL を AI エージェントに渡すことで、自分が作ったアプリが Keelson にデプロイできるかを確認してもらうことができます。

https://keelson.dev/ja/docs/reference/deploy-spec.txt

クイックスタート

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

このガイドでは、サンプルのWebアプリケーションをKeelsonにデプロイし、ブラウザでアクセスできることと、ログイン保護がデフォルトで有効になること を確認します。

このガイドを始める前に、次のものを用意してください。

  • Node.js と npm — ターミナルで node -vnpm -v を実行し、バージョンが表示されればOKです。インストールが必要な場合は Node.js公式サイト から推奨版(LTS)をダウンロードしてください。
  • Keelson のアカウント — まだの方は keelson.dev からサインアップしてください。
  • Claude Code や Codex など、Agent Skill を利用できるAIエージェント

インストール後、以下のコマンドで確認してください。

Terminal window
keelson --version

あなたのマシンをKeelsonのアカウントと紐付けます。以下のコマンドを実行してください。

Terminal window
keelson auth login

ブラウザが開き、ログイン画面が表示されます。ログインが完了すると、ターミナルに戻って操作を続けられます。

Keelsonでは、デプロイやデプロイ状態の確認(ログの確認)をAIエージェントに任せることができます。AIエージェントがKeelsonを操作するための Skill を、以下のコマンドでインストールしてください。

Terminal window
npx skills add https://github.com/keelsonhq/agent-skills --skill xxxxxx

デプロイのテスト用に、シンプルなPython (FastAPI) アプリを用意しました。このサンプルアプリには、認証やセキュリティに関するコードは一切含まれていません。

  1. sample-web (GitHub) からZIPファイルをダウンロードし、デスクトップなどに展開します。
  2. 展開したフォルダを、普段お使いのAIエージェント(Claude Codeなど)で開きます。

6. AIエージェントにデプロイを指示する

Section titled “6. AIエージェントにデプロイを指示する”

ここがKeelsonの醍醐味です。複雑なコマンドを打つ必要はありません。AIエージェントのチャット欄に、一言こう指示してください。

指示の例: 「Skillを使って、このアプリをKeelsonにデプロイして」

AIエージェントが keelson.yaml を読み取り、自動的にビルドとデプロイを開始します。デプロイには通常1〜2分かかります。その間、AIがサーバーの構築やセキュリティ設定をすべて代行しています。成功すると、AIが以下のような公開URLを教えてくれます。

https://your-app-name.keelson.run/

デプロイされたURLをブラウザで開いてみましょう。

  • ログイン済みブラウザ: アプリが表示されます。
  • シークレットウィンドウ: URLを開くと、Keelsonのログイン画面が表示されます。

これが Security by Default です。アプリのコードに認証処理を書かなくても、Keelson がデフォルトでログイン保護を適用します。

Keelson 認証画面(アテ画像)

基本コンセプト

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson は、社内やチームで共有するアプリを安全に公開するための実行基盤です。

ユーザーはアプリそのものの開発に集中し、公開・認証・共有に必要な仕組みは Keelson が引き受けます。このページでは、その考え方を説明します。

リクエストはどのようにアプリへ届くのか

Section titled “リクエストはどのようにアプリへ届くのか”

Keelson にデプロイされたアプリには、ユーザーのブラウザから直接アクセスが届くわけではありません。すべてのリクエストは、まず Keelson Proxy を通ります。

プロキシ構成図(アテ画像)

ユーザーが Keelson にデプロイされたアプリの URL を開くと、リクエストは次の順序で処理されます。

  1. 公開URLから、どのアプリへのアクセスかを特定する
  2. Keelson Proxy がログイン状態を確認する
  3. アプリへのアクセス権限を確認する
  4. 許可された場合のみ、リクエストをアプリへ転送する
  5. アプリのレスポンスをユーザーに返す

重要なのは、認証とアクセス制御の判断がアプリ本体の外側で行われることです。そのため、アプリ開発者は認証画面やセッション管理を毎回自前で実装しなくても、共有前提のアプリを安全に公開できます。

Keelson では、認証とアクセス制御の責務をアプリ本体の外側に分離しています。アプリは業務ロジックに集中しつつ、共有時のセキュリティはプラットフォーム側で一貫して扱えます。

なぜ認証をアプリに書かなくてよいのか

Section titled “なぜ認証をアプリに書かなくてよいのか”

Keelson では、アプリをデプロイした瞬間からログイン保護が有効になります。これを Security by Default と呼んでいます。

  • セキュリティは後付けではなく、最初から組み込まれている
  • 「動いた後に認証を足す」のではなく、「公開した時点で安全」
  • Quickstart で体験した、シークレットウィンドウでのログイン画面がこの仕組みの結果

Keelson が単なるホスティングではなく、社内アプリのための実行基盤である理由がここにあります。

Keelson はアプリの入口でログイン保護とアクセス制御を提供します。アプリ内部の業務ルールに基づく制御が必要な場合は、アプリ側で追加の実装を行います。

責任分界: アプリが担うこと / Keelson が担うこと

Section titled “責任分界: アプリが担うこと / Keelson が担うこと”

Keelson を使うとき、開発者が関わる範囲と Keelson が引き受ける範囲は明確に分かれています。

アプリが担うことKeelson が担うこと
UIデプロイ先の用意
業務ロジック公開URL
APIログイン保護
データ処理アプリへのアクセス制御
実行環境の管理

この分担があるため、アプリの開発者はインフラやセキュリティの構築に時間を割く必要がありません。

なぜ Keelson は社内・チーム共有に向いているのか

Section titled “なぜ Keelson は社内・チーム共有に向いているのか”

Keelson は、ローカルで一人だけが使うアプリのための基盤ではありません。チームや社内で安全に共有することを前提に設計されています。

そのため、以下の機能がプラットフォームに組み込まれています。

  • 公開URL — デプロイするだけでチームに共有できるURLが発行される
  • ログイン保護 — 許可されたメンバーだけがアクセスできる
  • メンバー管理 — 誰がどのアプリにアクセスできるかを制御できる

これらの詳細は、以下のページで説明しています。

まずアプリを動かし、細かい設定はあとから足す

Section titled “まずアプリを動かし、細かい設定はあとから足す”

最初はアプリを載せて動かすことに集中すれば十分です。

Keelson の設定は段階的に進められます。クイックスタート で触れた体験は最小構成の入り口であり、必要に応じて以下のような設定をあとから追加できます。

アプリを作る


対応アプリ種類

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson は、社内やチームで共有する Web アプリ・API・定期実行ジョブを安全にデプロイ・公開するための実行基盤です。

AI(ChatGPT、Claude、Manus など)で生成した小〜中規模の業務アプリに特に向いています。

想定しているアプリの例:

  • 社内ツール — 顧客管理、案件管理、在庫管理など
  • 管理画面 — データの閲覧・編集用ダッシュボード
  • 連携アプリ — Slack / Notion / Google Sheets との自動連携
  • 軽量な自動化処理 — CSV取込、定期集計、通知バッチ
  • バックオフィス向けアプリ — 承認申請、日報・レポート生成

フォーム+一覧表示+DB。CRUD 操作が中心の典型的な業務アプリで、Keelson Managed SQLite(libSQL・db.mode: libsql)がそのまま使えます。

テキスト検索 UI+バックエンド API。社内ナレッジを検索・閲覧するためのアプリで、認証付きで安全に社内公開できます。

ファイルアップロード+加工処理+ダウンロード。定型業務の自動化に最適で、Keelson なら非エンジニアにも URL を共有するだけで使ってもらえます。

フォーム送信+ステータス管理+通知。ワークフロー系の小さなアプリで、チーム内のメンバー管理と組み合わせてアクセス制御できます。

入力フォーム+テンプレート出力。日次・週次の報告を定型化するアプリで、定期実行ジョブ(cron)と組み合わせて自動集計も可能です。

Webhook 受信+API 呼び出し。外部サービスとのデータ連携を行うアプリで、Web アプリ+定期ジョブの組み合わせで構成できます。

cron ジョブのみで動く構成。売上集計、ログ解析、通知送信など、UI なしで定期実行だけを行うケースにも対応しています。

チャット UI+LLM API 呼び出し。社内向けの AI アシスタントを、認証付きで安全にチームに提供できます。


対応ランタイム / フレームワークの考え方

Section titled “対応ランタイム / フレームワークの考え方”

Keelson は特定のフレームワーク専用の PaaS ではありません。HTTP サーバーとして起動する標準的な構成のアプリであれば、フレームワークを問わず動かせます。

ランタイム用途
python-slim軽量な Python アプリ(API、テキスト処理など)
python-mediaメディア処理向け Python(画像・動画ライブラリ含む)
node-slim軽量な Node.js アプリ
node-mediaメディア処理向け Node.js
go-slim軽量な Go アプリ
go-mediaメディア処理向け Go
  • Web アプリ — HTTP サーバーとして起動し、ブラウザからアクセスするもの
  • API サーバー — JSON API を提供するバックエンド
  • 定期実行ジョブ(cron) — スケジュールに従って定期的にコマンドを実行するもの
  • ワーカープロセス — Web アプリと並行して動くバックグラウンド処理

フレームワークの例: FastAPI、Flask、Express、Next.js、Hono、Gin など。keelson.yamlcommand で起動できるものであれば動作します。


以下に当てはまるなら、Keelson が適しています。

  • 社内利用が前提 — チームや社内のメンバーに限定して公開したい
  • 認証をかけて安全に公開したい — ログイン保護をアプリに実装せずに済ませたい
  • 小さなアプリを複数動かしたい — 1つのワークスペースで複数アプリを管理できる
  • SQLite を使いたい — Keelson Managed SQLite(libSQL・db.mode: libsql)がプラットフォーム標準で使える(/data は揮発)
  • AI に作らせたアプリをまず動かしたい — Dockerfile 不要、keelson.yaml だけでデプロイできる
  • 開発者以外にも見せたい — URL を共有するだけで、非エンジニアもブラウザからアクセスできる

以下のようなケースには、Keelson は最適ではありません。

  • 超高トラフィックな一般公開サービス — 大規模なコンシューマー向けサービスは想定外
  • 厳しい低レイテンシが必要な edge 寄りの用途 — CDN エッジでの実行には非対応
  • 複雑な分散システム — マイクロサービス間の高度なオーケストレーションには向かない
  • GPU 前提の重い推論基盤 — GPU インスタンスは提供していない
  • 特殊なミドルウェア前提の構成 — Redis、PostgreSQL(外部)、Kafka などを自前で構成する必要がある場合
  • 厳密なネットワーク制御や専有インフラが必須 — VPC ピアリング、専用ノードなどが初期要件の場合

判断チャート: あなたのアプリは Keelson 向きか

Section titled “判断チャート: あなたのアプリは Keelson 向きか”

以下の質問に順番に答えてください。3分で判断できます。

1. 利用者は社内・チームメンバーが中心ですか? → いいえ → 不特定多数への公開サービスには向いていません

2. アプリは Web UI または API を提供しますか? → いいえ → 定期実行ジョブ(cron)だけの構成でも対応可能です。それ以外の形態は対象外です

3. Node.js / Python / Go のいずれかで動きますか? → いいえ → 現時点ではこの3つのランタイムに対応しています

4. GPU や特殊なミドルウェア(Redis、Kafka など)は必要ですか? → はい → 現時点では対応していません

5. 専有インフラや厳密なネットワーク制御は初期要件ですか? → はい → Enterprise プランでの対応を検討中です。お問い合わせください

すべてクリアした場合 → Keelson で動かせます。


もっとも単純な構成でデプロイする例を示します。

ディレクトリ構成:

my-app/
├── keelson.yaml
├── requirements.txt
└── app.py

keelson.yaml:

slug: my-app
runtime: python-slim
command: "pip install --user -r requirements.txt && python app.py"
env:
PORT: "8080"

app.py:

from fastapi import FastAPI
import uvicorn, os
app = FastAPI()
@app.get("/")
def index():
return {"message": "Hello from Keelson"}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))

ディレクトリ構成:

my-app/
├── keelson.yaml
├── package.json
└── index.js

keelson.yaml:

slug: my-app
runtime: node-slim
command: "npm install && npm start"
env:
PORT: "8080"
NODE_ENV: "production"

index.js:

const express = require("express");
const app = express();
const port = process.env.PORT || 8080;
app.get("/", (req, res) => {
res.json({ message: "Hello from Keelson" });
});
app.listen(port, "0.0.0.0", () => {
console.log(`Listening on port ${port}`);
});

デプロイが完了すると、https://my-app.keelson.run/ のような URL が発行されます。この URL にアクセスすると、ログイン済みのメンバーだけがアプリを利用できます。


不要です。keelson.yaml でランタイムと起動コマンドを指定するだけでデプロイできます。Keelson がビルドと実行環境の構築を行います。

フロントエンド単体(静的サイト)も置けますか?

Section titled “フロントエンド単体(静的サイト)も置けますか?”

はい。keelson.yamlassets を設定すれば、ビルド済みの静的ファイルをホストできます。

はい。UI を持たない JSON API サーバーも問題なくデプロイできます。

ビルドとランタイム

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson にアプリをデプロイすると、以下の流れで公開されます。

ソースコード → CLI / AI エージェントが送信 → Keelson がビルド → コンテナとして起動 → 公開 URL 発行
認証・アクセス制御が前段で適用
  1. ソースコードを送る — CLI(keelson deploy)または AI エージェントの Skill がソースコードと keelson.yaml を Keelson に送信します
  2. Keelson がビルドする — 指定されたランタイムに基づいて、依存関係のインストールと実行環境の構築が自動で行われます
  3. コンテナとして起動する — ビルドされたアプリが keelson.yamlcommand に従って起動します
  4. 公開 URL が発行されるhttps://<slug>.keelson.run/ の URL が払い出されます
  5. 認証・アクセス制御が適用される — すべてのリクエストは認証プロキシを経由し、ログイン済みの許可されたメンバーだけがアクセスできます

開発者がビルドやインフラの設定を行う必要はありません。keelson.yaml に必要な情報を記述すれば、あとは Keelson が処理します。


Keelson では、1つのアプリが1つの実行単位になります。アプリの種類に応じて、以下の形態で動作します。

HTTP サーバーとして起動し、リクエストを受け付け続けます。ブラウザからアクセスする UI や、JSON API を返すバックエンドがこの形態です。

スケジュールに従って定期的にコマンドを実行します。集計処理、通知送信、データ同期などに使います。Web アプリとは独立して定義でき、Web アプリを持たない cron だけの構成も可能です。

Web アプリと並行して動くバックグラウンド処理です。キュー処理やデータの非同期処理に使います。Web アプリが存在する場合にのみ追加できます。

これらは組み合わせて使えます。

構成説明
Web アプリのみもっとも一般的な構成
Web アプリ + cronアプリに加えて定期処理を実行
Web アプリ + ワーカーアプリに加えてバックグラウンド処理を実行
cron のみUI なしで定期実行だけを行う

アプリには次の状態があります。

  • 稼働中(running) — 実行中。「同時に使えるアプリ数」の枠を消費します
  • スリープ(sleep) — 自動スリープ。無アクセスで自動的に停止し、アクセスがあると自動で起動します
  • サスペンド(suspended) — 手動で停止した状態。アクセスがあっても起動しません。データ・URL・設定はすべて保持され、ダッシュボードからいつでも再開できます

スリープ中のアプリはアクセスで自動起動しますが、サスペンド中のアプリは手動で再開するまで起動しません。

再デプロイすると、新しいコードでアプリが置き換えられます。ローカルの /data は揮発(一時領域)で永続化されないため、永続データは Managed SQLite(db.mode: libsql)に置いてください。

ダッシュボードのアプリ一覧では、ワークスペースのアプリを台帳としてまとめて確認できます。各アプリについて次の情報が表示されます。

  • 状態 — 稼働中 / スリープ / サスペンド / 未デプロイ / エラー
  • 作成者 — アプリを作成したメンバー
  • アクセス範囲 — そのアプリを利用できる範囲(全員に公開されている場合は「全員」、限定されている場合は対象人数とグループ)
  • 最終アクセス — 最後にアクセスがあった日時(一度もアクセスがない場合は「未アクセス」)
  • 最終デプロイ — 最後にデプロイした日時

作成者や利用状況で並べ替えたり、「作成者: 自分」で絞り込んだりできます。

なお、アプリの保存数に上限はありません。プランの上限は、同時に動かせるアプリの数(「同時に使えるアプリ数」)にのみ適用されます。使っていないアプリ(スリープ / サスペンド)は枠を消費しません。


対応している言語・ランタイム

Section titled “対応している言語・ランタイム”

現時点で以下のランタイムに対応しています。

ランタイム言語用途
python-slimPython軽量(API、テキスト処理、自動化など)
python-mediaPythonメディア処理向け(画像・動画・PDF ライブラリを含む)
node-slimNode.js軽量(Web アプリ、API など)
node-mediaNode.jsメディア処理向け(画像・PDF 処理ライブラリを含む)
go-slimGo軽量
go-mediaGoメディア処理向け

keelson.yamlruntime フィールドで指定します。

runtime: python-slim

依存関係は command 内でインストールします。

Python:

command: "pip install --user -r requirements.txt && python app.py"

Node.js:

command: "npm install && npm start"

Go:

# Keelson 側で deploy 時に `./app` がビルドされます。
command: "./app"

keelson.yamlcommand で起動コマンドを指定します。

# 文字列形式(/bin/sh -c で実行)
command: "python app.py"
# リスト形式(exec で直接実行)
command:
- python
- app.py

Web アプリは環境変数 PORT で指定されたポートで HTTP リクエストを待ち受けてください。keelson.yamlenv で設定します。

env:
PORT: "8080"

アプリ側のコード例:

import os
port = int(os.environ.get("PORT", 8080))
const port = process.env.PORT || 8080;

HTTP サーバーは必ず 0.0.0.0 で listen してください。127.0.0.1localhost ではリクエストが届きません。

uvicorn.run(app, host="0.0.0.0", port=port)
app.listen(port, "0.0.0.0");

Keelson のデプロイには2つのフェーズがあります。

ビルド時実行時
何が起きるかソースコードの取得、依存関係のインストール、実行環境の構築アプリの起動、リクエストの処理
環境変数keelson.yamlenv で定義した値が利用可能同じ env の値に加え、Keelson が設定するシステム環境変数が利用可能
ネットワーク外部パッケージレジストリ(npm, PyPI など)への通信が可能外部 API への通信が可能
データ永続化/data はまだ利用できない/data は揮発(一時領域)で永続化されない。永続データは Managed SQLite(db.mode: libsql)に置く
  • ビルドログ — 依存関係のインストールやビルド処理の出力。ビルドが失敗した場合の原因特定に使います
  • 実行ログ — アプリの標準出力・標準エラー出力。実行中のエラーやリクエスト処理の確認に使います

いずれもダッシュボードから確認できます。


  • CPU とメモリはプランの Compute Class に応じて割り当てられます
  • リソースはワークスペース内の全アプリに共通の性能帯が適用されます(アプリごとの個別設定ではありません)
  • root 権限は使えません — アプリは非 root ユーザーとして実行されます
  • systemd やデーモン管理は使えません — プロセス管理は command で起動した単一プロセスが基本です
  • ローカルファイルは永続化されません/data を含むローカルディスクへの書き込みは再起動・再デプロイ・scale-to-zero で失われます。永続データは Managed SQLite(db.mode: libsql)に置いてください
  • HTTP リクエストには一般的なタイムアウトが適用されます
  • 定期実行ジョブ(cron)の timeout は 1〜3,600 秒で設定可能です(デフォルト: 300 秒)
  • アプリから外部の API やサービスへの通信はデフォルトで可能です

多くのフレームワークはデフォルトで 127.0.0.1(localhost)で listen します。Keelson ではリクエストがコンテナ外から届くため、0.0.0.0 を明示する必要があります。

# NG
uvicorn.run(app, host="127.0.0.1", port=port)
# OK
uvicorn.run(app, host="0.0.0.0", port=port)

ポートがハードコードされている

Section titled “ポートがハードコードされている”

ポート番号をコードに直接書くと、Keelson の環境で一致しない場合があります。環境変数 PORT から読み取ってください。

// NG
app.listen(3000);
// OK
app.listen(process.env.PORT || 8080);

依存関係がインストールされていない

Section titled “依存関係がインストールされていない”

command に依存関係のインストールを含め忘れると、実行時にモジュールが見つからずエラーになります。

# NG
command: "python app.py"
# OK
command: "pip install --user -r requirements.txt && python app.py"

エントリポイントのファイル名やパスが間違っていると、アプリが起動しません。ローカルで同じコマンドを実行して動作を確認してください。

ローカルでは動くが Keelson では落ちる

Section titled “ローカルでは動くが Keelson では落ちる”

よくある原因:

  • ローカルにだけ存在するファイルやディレクトリに依存している
  • 環境変数が設定されていない
  • localhost 前提の外部サービス接続(ローカル DB など)
  1. ビルドログを確認する — ダッシュボードでビルドの出力を確認し、依存関係のインストールが成功しているか確認
  2. 実行ログを確認する — アプリの起動時エラーやランタイムエラーがないか確認
  3. keelson.yaml を確認するruntimecommandenv の設定が正しいか見直す

サンプル: Node / Python の最小構成

Section titled “サンプル: Node / Python の最小構成”

必要ファイル:

my-api/
├── keelson.yaml
├── requirements.txt
└── app.py

keelson.yaml:

slug: my-api
runtime: python-slim
command: "pip install --user -r requirements.txt && python app.py"
env:
PORT: "8080"
PYTHONUNBUFFERED: "1"

requirements.txt:

fastapi
uvicorn

app.py:

from fastapi import FastAPI
import uvicorn, os
app = FastAPI()
@app.get("/")
def index():
return {"message": "Hello from Keelson"}
if __name__ == "__main__":
port = int(os.environ.get("PORT", 8080))
uvicorn.run(app, host="0.0.0.0", port=port)

必要ファイル:

my-app/
├── keelson.yaml
├── package.json
└── index.js

keelson.yaml:

slug: my-app
runtime: node-slim
command: "npm install && npm start"
env:
PORT: "8080"
NODE_ENV: "production"

package.json:

{
"name": "my-app",
"scripts": { "start": "node index.js" },
"dependencies": { "express": "^4" }
}

index.js:

const express = require("express");
const app = express();
const port = process.env.PORT || 8080;
app.get("/", (req, res) => {
res.json({ message: "Hello from Keelson" });
});
app.listen(port, "0.0.0.0", () => {
console.log(`Listening on port ${port}`);
});

デプロイが完了すると https://my-app.keelson.run/ のような URL が発行されます。ブラウザでアクセスし、{"message": "Hello from Keelson"} が表示されれば成功です。


AI に依頼するときのプロンプト例

Section titled “AI に依頼するときのプロンプト例”

Keelson は AI で生成したアプリをそのままデプロイできるように設計されています。以下のようなプロンプトを AI に渡すと、Keelson 互換のアプリを生成しやすくなります。

Keelson で動く FastAPI アプリを作ってください。環境変数 PORT で指定されたポートで 0.0.0.0 を listen してください。

データベースは Keelson Managed SQLite(libSQL)を使い、db.mode: libsql を宣言してください。接続情報は環境変数 KEELSON_DB_URL / KEELSON_DB_AUTH_TOKEN から読み取ってください(/data は揮発なのでファイル DB は使わない)。

毎日午前3時にデータを集計するバッチ処理を追加してください。メインの Web アプリとは別に cron ジョブとして実行します。

keelson.yaml の生成を依頼する場合

Section titled “keelson.yaml の生成を依頼する場合”

このアプリ用の keelson.yaml を作成してください。ランタイムは python-slim、起動コマンドは pip install --user -r requirements.txt && python app.py です。

AI にアプリを生成させるとき、以下の3点を伝えるとスムーズです。

  1. ポートPORT 環境変数から読み取り、0.0.0.0 で listen する
  2. データ保存先 — ファイルや SQLite は /data ディレクトリに置く
  3. 起動方法 — 単一のコマンドで起動できるようにする

Keelson のビルド・ランタイムが向いているケース

Section titled “Keelson のビルド・ランタイムが向いているケース”
  • 標準的な Node.js / Python / Go アプリ — 特殊なビルドツールチェーンが不要
  • AI で生成したアプリをすぐに動かしたい — Dockerfile を書かずにデプロイできる
  • 依存関係が pip / npm / go mod で管理されている — command 内でインストールするだけ
  • HTTP サーバーとして起動するアプリ — ポートを listen するだけで公開される
  • Dockerfile による細かいビルド制御が必要 — Keelson は独自の Dockerfile を使えません
  • システムパッケージの追加インストールが必要apt-get 等で追加するパッケージが多い場合は media ランタイムで対応できるか確認してください
  • root 権限やデーモンプロセスが前提 — アプリは非 root で動作し、systemd は使えません
  • ビルド成果物を細かくキャッシュしたい — ビルドキャッシュの制御は Keelson に委ねる形です

使えません。Keelson はランタイムを選択し、command で起動する方式です。Dockerfile の代わりに keelson.yaml でランタイムと起動コマンドを指定します。

ビルドにかかる時間はどのくらいですか?

Section titled “ビルドにかかる時間はどのくらいですか?”

依存関係の量によりますが、一般的な小〜中規模のアプリであれば1〜2分程度です。

外部の API やサービスに接続できますか?

Section titled “外部の API やサービスに接続できますか?”

はい。アプリから外部への通信はデフォルトで可能です。

ビルドが失敗したらどうすればいいですか?

Section titled “ビルドが失敗したらどうすればいいですか?”

ダッシュボードでビルドログを確認してください。AI エージェントにログを渡して「このビルドエラーを修正して」と依頼するのも有効です。

ストレージとデータ

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson のアプリには、2種類のファイルシステム領域があります。

領域永続性用途
アプリディレクトリ(ソースコード等)揮発(置き換わる)アプリのコード、依存パッケージ
/data揮発(再起動・scale-to-zero で失われる)一時的なスクラッチ領域

/data に書いたファイルは永続化されません(再起動・再デプロイ・scale-to-zero で失われます)。永続的な関係データは Keelson Managed SQLite(db.mode: libsql を使ってください。汎用ファイルの永続 I/O は後続のデータファイル SDK で提供予定です。


ファイルの保存(アプリデータファイルとメディア)

Section titled “ファイルの保存(アプリデータファイルとメディア)”

アプリはファイルを保存できます。保存が完了した時点でデータは永続化されています(バックグラウンド同期はありません)。

  • アプリデータファイル — アプリが名前を付けて更新するファイル(実行状態・設定・小さなキャッシュなど)。書き込みはファイル全体を対象とし、完了した時点で反映されます。これらのファイルはアプリの内部用で非公開です。
  • メディア — 画像や PDF などのアップロード・生成メディアは専用の保存先にアップロードされ、ID で参照して URL で配信できます。

リクエストごとに読み書きする構造データには、マネージドデータベースを利用してください。


永続データは Keelson Managed SQLite(libSQL) に置きます。ローカルの /data は揮発(一時領域)で、再起動・再デプロイ・scale-to-zero で失われます。

  • アプリデータ(顧客・案件・ログなど) — Managed SQLite(db.mode: libsql
  • アップロードファイル / 生成済みレポート — 現時点では永続化の口はなく、後続のデータファイル SDK で提供予定(/data は一時領域なので永続保存には使えない)
  • 再生成可能なキャッシュ / 一時ファイル/tmp または /data(どちらも揮発)

/data は揮発(一時領域)で永続化されないため、失って困るものは置かないでください。用途別の置き場所:

  • 永続データ(業務データ・DB) — Keelson Managed SQLite(db.mode: libsql
  • アップロード / 巨大なバイナリ — 外部のオブジェクトストレージ(S3 互換サービスなど)へアプリから直接保存
  • 一時ファイル — 処理中だけ必要なファイルは /tmp または /data(どちらも揮発)を使い、処理後に削除
  • 再生成可能なキャッシュnode_modules やビルド成果物は永続化不要
  • 大規模ログ — アプリログは Keelson のログ機能で閲覧できます

新規アプリでは Keelson Managed SQLite の利用を推奨します。プラットフォームがアプリごとに専用のマネージド SQLite(libSQL)データベースを自動でプロビジョニングし、テナント / アプリ単位で DB レベルに分離します。

  • セットアップ不要 — 接続情報(KEELSON_DB_URL / KEELSON_DB_AUTH_TOKEN)が環境変数で自動注入されます。契約・設定は不要で無料枠内で使えます
  • テナント分離 — 各アプリのクレデンシャルは自分の DB だけにスコープされ、他アプリ / 他テナントの DB には到達できません
  • 即時耐久 — 書き込みはプライマリへライトスルーされ、コミット時点で永続化されます(データ損失窓なし)
  • 国内配置 — プライマリは東京に配置されます
  • 時刻復元(PITR) に対応(保持期間はプラン依存)

libSQL クライアントを利用できる JS/TS・Python アプリでそのまま使えます。利用するには keelson.yamldb.mode: libsql を明示指定します(db.mode のスキーマ既定は none で、Managed SQLite はオプトインです)。


外部データベースを使う(db.mode: none

Section titled “外部データベースを使う(db.mode: none)”

自動で用意されるデータベースは設定不要・無料枠内で使えますが、Postgres・MySQL・外部の libSQL など自分で契約したデータベースを使いたい場合は keelson.yamldb.mode: none を指定し、接続情報を secrets として自分で設定します。プラットフォームは外部 DB の接続情報を注入しません(自分で用意した接続情報がそのまま有効になります)。

ファイル SQLite を前提とするフレームワーク(Django 等)を載せる場合も、この外部データベース経路(db.mode: none + 外部 Postgres など)を使います。ファイル SQLite のまま永続化する経路は提供していません。


ファイル SQLite は永続化されません

Section titled “ファイル SQLite は永続化されません”

/data に SQLite ファイルを直接置く構成は永続化されません。ファイル SQLite は再起動・scale-to-zero で失われ、デプロイ時に検出して fail-closed で失敗させます。better-sqlite3sqlite3 のようなファイル SQLite クライアントを使っているアプリは、libSQL クライアントへ移行して Keelson Managed SQLite(db.mode: libsql を利用してください。再生成可能な一時 SQLite は db.local_sqlite/tmp / :memory:)として明示宣言できます。


アップロードファイルの永続保存の口は現時点では提供していません。 /data は揮発(一時領域)で、再起動・再デプロイ・scale-to-zero で失われるため、アップロードファイルの保存先には使えません。汎用ファイルの永続 I/O は後続のデータファイル SDK で提供予定です。それまでは、外部のオブジェクトストレージ(S3 互換など)へアプリから直接保存する構成を検討してください(Keelson はアウトバウンド接続を許可します)。


Keelson は Managed SQLite(libSQL) のスナップショットを毎日自動で取得します。保持日数はプランによって異なります。

プランスナップショット保持
Starter1日分
Plus3日分
Team7日分
Business14日分

手動スナップショットは、SQLite 管理画面から任意のタイミングで取得できます(全プラン)。

対象バックアップされるか
Managed SQLite(libSQL)のデータされる(日次スナップショット + 時刻復元)
/data 配下のファイルされない(/data は揮発・永続化されない)
アプリのソースコードされない(デプロイ時に毎回送信される)
環境変数されない(ダッシュボードで管理)

アプリのコードは Git などのバージョン管理で保持し、永続データは Managed SQLite に置いてスナップショットで保護してください。

スナップショットからの復元が必要な場合は、ダッシュボードから操作できます。復元はアプリ単位で行われ、他のアプリのデータには影響しません。


外部データベースや外部ストレージを使うべき場合

Section titled “外部データベースや外部ストレージを使うべき場合”

Managed SQLite(libSQL)は多くの社内アプリに十分ですが、以下のケースでは外部サービスの利用を検討してください。

ケース理由選択肢
データ量が数 GB を超えるSQLite のパフォーマンスが低下する可能性PostgreSQL(アドオンで専用 DB を利用可能)
同時書き込みが非常に多いSQLite はライター1つの制約があるPostgreSQL、MySQL
BI や基幹系と直接連携するデータを外部システムから参照する必要がある共有の PostgreSQL、データウェアハウス
厳密な運用要件があるポイントインタイムリカバリや複雑なレプリケーションが必要マネージド PostgreSQL
大容量ファイルを大量に扱うストレージ容量を超える可能性S3 互換オブジェクトストレージ

顧客管理や在庫管理など。データは Managed SQLite(db.mode: libsql に保存する。

db:
mode: libsql

CSV の取込・加工や定期集計を行うアプリ。集計結果は Managed SQLite に保存し、/tmp(揮発)を中間ワークとして使う。永続化したい中間生成物は Managed SQLite か外部オブジェクトストレージに置く。

社内 RAG や AI チャットのバックエンド。ナレッジのメタデータ・埋め込みは Managed SQLite に保存する。参照ドキュメント等の大きな添付は外部オブジェクトストレージ(S3 互換)へアプリから直接保存する(/data は揮発)。


ファイルにデータを保存して消える

Section titled “ファイルにデータを保存して消える”

ローカルファイル(/tmp・アプリディレクトリ・/data を含む)に書き込んだデータは永続化されず、再起動・再デプロイ・scale-to-zero で失われます。永続化したいデータは Managed SQLite(libSQL) に置いてください。

# NG — ローカルファイルは揮発(/data も含めて永続化されない)
db_path = "./data.db"
db_path = "/tmp/data.db"
db_path = "/data/main.db"
# OK — Managed SQLite(libSQL)に接続する
import libsql
conn = libsql.connect(database=os.environ["KEELSON_DB_URL"],
auth_token=os.environ["KEELSON_DB_AUTH_TOKEN"])

better-sqlite3 / sqlite3 などのファイル SQLite クライアントで /data にファイル DB を作る構成は永続化されず、デプロイ時に検出して失敗します。libSQL クライアントへ移行して Managed SQLite(db.mode: libsql)を使ってください。

バックアップの仕組みを誤解する

Section titled “バックアップの仕組みを誤解する”

スナップショットは日次で自動取得されますが、保持日数はプランによって異なります。重要なデータを扱う場合は、プランの保持日数を確認し、必要に応じてアプリ側でもエクスポート機能を用意してください。

不要になったファイルを削除せずに放置すると、ストレージ容量を圧迫します。ストレージ容量にはスナップショットやログも含まれるため、アプリデータだけで上限いっぱいにならないよう注意してください。

ファイル SQLite をハードコードする

Section titled “ファイル SQLite をハードコードする”

sqlite3.connect("/data/main.db")better-sqlite3 のようにローカルのファイル SQLite を使う構成は、/data が揮発なので永続化されず、デプロイ時に検出して失敗します。libSQL クライアントへ移行してください。


Python: Managed SQLite(libSQL)に保存する

Section titled “Python: Managed SQLite(libSQL)に保存する”
import os, libsql
def get_db():
conn = libsql.connect(
database=os.environ["KEELSON_DB_URL"],
auth_token=os.environ["KEELSON_DB_AUTH_TOKEN"],
)
conn.execute("""
CREATE TABLE IF NOT EXISTS items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
return conn
conn = get_db()
conn.execute("INSERT INTO items (name) VALUES (?)", ("サンプルアイテム",))
conn.commit()

keelson.yaml:

slug: my-app
runtime: python-slim
command: "pip install --user -r requirements.txt && python app.py"
db:
mode: libsql # KEELSON_DB_URL / KEELSON_DB_AUTH_TOKEN が注入される
env:
PORT: "8080"

Node.js: Managed SQLite(libSQL)に保存する

Section titled “Node.js: Managed SQLite(libSQL)に保存する”
import { createClient } from "@libsql/client";
const db = createClient({
url: process.env.KEELSON_DB_URL,
authToken: process.env.KEELSON_DB_AUTH_TOKEN,
});
await db.execute(`
CREATE TABLE IF NOT EXISTS items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
await db.execute({ sql: "INSERT INTO items (name) VALUES (?)", args: ["サンプルアイテム"] });

Managed SQLite が向いているケース

Section titled “Managed SQLite が向いているケース”
  • 社内アプリの業務データ — 顧客情報、案件、在庫など、libSQL で十分な規模
  • AI で生成したアプリをすぐに動かしたい — 外部 DB の設定なしで db.mode: libsql だけで永続 DB が使える
  • 小さなアプリを複数動かしたい — アプリ / テナントごとに DB が分離されている

Managed SQLite が向いていないケース

Section titled “Managed SQLite が向いていないケース”
  • データ量が数十 GB を超える — ストレージ容量とパフォーマンスの両面で外部 DB を検討
  • 複数システムからの同時アクセスが必要 — Managed SQLite はアプリ内からのアクセスが基本
  • ポイントインタイムリカバリが必須 — スナップショットは日次のため、より細かい復元が必要なら外部 DB を検討
  • BI ツールや基幹システムとの直接連携 — 外部からクエリできるデータベースが必要

ストレージの容量上限はどのくらいですか?

Section titled “ストレージの容量上限はどのくらいですか?”

プランによって異なります(Starter: 10 GB 〜 Business: 100 GB)。この容量には Managed SQLite のデータ、スナップショット、アーティファクトの合計が含まれます(ローカル /data は揮発で容量対象外)。追加ストレージはアドオンで購入できます。

再デプロイするとデータは消えますか?

Section titled “再デプロイするとデータは消えますか?”

/data に書いたデータは消えます。 /data は揮発(一時領域)で、再起動・再デプロイ・scale-to-zero で失われます。永続データは Keelson Managed SQLite(db.mode: libsql に置いてください(再デプロイ後も保持され、日次スナップショットの対象です)。

SQLite 以外のデータベースは使えますか?

Section titled “SQLite 以外のデータベースは使えますか?”

Keelson Managed SQLite(libSQL)を第一推奨とします。外部の PostgreSQL や MySQL に接続することも可能です(アウトバウンド接続は許可されています)。/data 上のファイル SQLite は永続化されないため、libSQL クライアントへ移行してください。

他のアプリから /data にアクセスできますか?

Section titled “他のアプリから /data にアクセスできますか?”

できません。/data はアプリごとに完全に分離されています。アプリ間でデータを共有する必要がある場合は、API 経由でやり取りしてください。

バックアップからの復元にかかる時間はどのくらいですか?

Section titled “バックアップからの復元にかかる時間はどのくらいですか?”

データ量によりますが、一般的な社内アプリの規模であれば数分で完了します。


「データベースは Keelson Managed SQLite(libSQL)を使い、db.mode: libsql を宣言してください」

「DB 接続は環境変数 KEELSON_DB_URL / KEELSON_DB_AUTH_TOKEN から読み取り、libSQL クライアントで接続してください(ファイル SQLite は使わない)」

「アップロードファイルなど永続保存が必要なものは、外部オブジェクトストレージ(S3 互換)へ直接保存してください(/data は揮発)」

定期実行ジョブ(Scheduled Jobs)

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson では、アプリの公開だけでなく、コードを定期的に自動実行できます。Web アプリと同じコードベース・同じ keelson.yaml でジョブを管理でき、社内業務の自動化に使えます。

代表的なユースケース:

  • 毎朝のレポート生成 — 売上や KPI を集計して /data に保存
  • 毎時間の API 同期 — 外部サービスからデータを取得して DB を更新
  • 毎日の Slack 通知 — 期限切れタスクや承認待ちのリマインド
  • 夜間の CSV 取込 — アップロードされた CSV を一括処理
  • 定期的なデータクリーンアップ — 古いログや一時ファイルの削除

Scheduled Jobs は「同時に使えるアプリ数」の枠を消費しません。Web アプリとは独立してカウントされます。


  1. keelson.yamlcrons にジョブを定義する
  2. デプロイすると、Keelson が定期実行ジョブとして登録する
  3. 指定したスケジュールに従って、コマンドが自動で実行される
  4. 実行ごとにログが記録される

ジョブの動作は、Web アプリの有無によって異なります。

構成動作
cron のみ(command なし)ジョブごとに独立して実行される
Web アプリ + cron(command あり)Web アプリと同じ実行環境内でジョブが動く

どちらの構成でも、ジョブの定義方法は同じです。

  • 実行結果(成功・失敗)はダッシュボードで確認できます
  • 標準出力・標準エラーがログとして記録されます
  • 実行回数は成功・失敗・リトライ・手動実行をすべて含みます

keelson.yamlcrons セクションでジョブを定義します。

slug: my-app
runtime: python-slim
crons:
- name: daily-report
schedule: "0 9 * * *"
command: "python report.py"
timeout: 120
フィールド必須デフォルト説明
nameはいジョブ名。小文字英数字とハイフン、1〜63 文字
scheduleはいcron 式(5フィールド)
commandはい実行するコマンド
timeoutいいえ300 秒タイムアウト。1〜3,600 秒

1つのアプリに最大10個のジョブを定義できます。

crons:
- name: hourly-sync
schedule: "0 * * * *"
command: "python sync.py"
- name: daily-cleanup
schedule: "0 3 * * *"
command: "python cleanup.py"
timeout: 60
- name: weekly-report
schedule: "0 9 * * 1"
command: "python weekly_report.py"
timeout: 600

トップレベルの env で定義した環境変数は、ジョブの実行時にも利用できます。

db:
mode: libsql
env:
SLACK_WEBHOOK_URL: "https://hooks.slack.com/..."
crons:
- name: notify
schedule: "0 9 * * *"
command: "python notify.py"

スケジュールは5フィールドの cron 式で指定します。

┌───────────── 分(0-59)
│ ┌─────────── 時(0-23)
│ │ ┌───────── 日(1-31)
│ │ │ ┌─────── 月(1-12)
│ │ │ │ ┌───── 曜日(0-6、0=日曜)
│ │ │ │ │
* * * * *
やりたいことcron 式説明
毎日 9:000 9 * * *毎日午前9時に実行
30分ごと*/30 * * * *毎時0分と30分に実行
毎時間0 * * * *毎時0分に実行
10分ごと*/10 * * * *10分間隔で実行
平日のみ 9:000 9 * * 1-5月〜金の午前9時に実行
毎月1日 0:000 0 1 * *月初に実行
毎日深夜 3:000 3 * * *夜間バッチ向き
毎分* * * * *テスト・デバッグ用

  • 入力: /data/sales/ 配下の CSV ファイル
  • 処理: 当日分を集計し、合計・件数を計算
  • 出力: /data/reports/daily-sales-YYYY-MM-DD.json に保存
crons:
- name: daily-sales
schedule: "0 8 * * *"
command: "python aggregate_sales.py"
timeout: 120

毎時間、外部 API からデータ同期

Section titled “毎時間、外部 API からデータ同期”
  • 入力: 外部サービスの REST API
  • 処理: 最新データを取得し、差分をデータベース(db.mode: libsql)に反映
  • 出力: Managed SQLite の該当テーブルが更新される
crons:
- name: hourly-sync
schedule: "0 * * * *"
command: "python sync_from_api.py"
timeout: 180
  • 入力: SQLite のレコード
  • 処理: expired_at が過去のレコードを削除
  • 出力: 削除件数をログに出力
crons:
- name: cleanup-expired
schedule: "0 2 * * *"
command: "python cleanup_expired.py"
timeout: 60
  • 入力: SQLite の週次データ
  • 処理: テンプレートからレポートを生成
  • 出力: /data/reports/weekly-YYYY-WXX.pdf に保存
crons:
- name: weekly-report
schedule: "0 9 * * 1"
command: "python generate_weekly_report.py"
timeout: 300

ジョブは同じスケジュールで繰り返し実行されます。途中で失敗して再実行されても、データが二重に作成されないように設計してください。

# NG — 毎回 INSERT すると重複する
db.execute("INSERT INTO reports (date, total) VALUES (?, ?)", (today, total))
# OK — UPSERT で既存データを上書き
db.execute("""
INSERT INTO reports (date, total) VALUES (?, ?)
ON CONFLICT(date) DO UPDATE SET total = excluded.total
""", (today, total))

デフォルトのタイムアウトは 300 秒(5分)です。処理に時間がかかる場合は timeout を明示的に設定してください。最大 3,600 秒(1時間)まで指定できます。

ジョブが失敗しても自動リトライは行われません。冪等に設計しておけば、次のスケジュールで自然にリカバリされます。重要なジョブでは、失敗時に Slack 通知を送るなどの仕組みを入れておくと安心です。

外部 API を呼び出すジョブでは、レート制限に注意してください。短い間隔(毎分など)で外部 API を叩くと、制限に引っかかる場合があります。

SQLite への書き込みを伴うジョブが、Web アプリと同じデータベースを使う場合、書き込みのタイミングが重なる可能性があります。SQLite は単一ライターの制約があるため、短時間の待ちが発生することがあります。通常の社内ツール規模であれば問題になりませんが、書き込み頻度が高い場合は注意してください。


ジョブの標準出力(printconsole.log)と標準エラーはすべてログとして記録されます。ダッシュボードからジョブ単位で確認できます。

デバッグ時は、処理の進捗やデータの状態を print で出力しておくと原因特定がしやすくなります。

import datetime
print(f"[{datetime.datetime.now()}] ジョブ開始")
# ... 処理 ...
print(f"処理件数: {count}")
print(f"[{datetime.datetime.now()}] ジョブ完了")
  1. 実行ログを見る — エラーメッセージやスタックトレースを確認
  2. 環境変数を確認する — API キーやデータベースパスが正しいか
  3. タイムアウトを確認する — 処理が timeout の秒数内に終わっているか
  4. 手元で再現する — 同じコマンドをローカルで実行してみる

Keelson のジョブログをそのまま AI エージェントに渡せば、エラーの原因特定と修正を依頼できます。

「このジョブのエラーログを確認して、原因を特定して修正してください」

AI エージェントがログを読み、コードの修正と再デプロイまで一連で対応できます。


Web アプリとジョブを組み合わせる

Section titled “Web アプリとジョブを組み合わせる”

Keelson の強みは、Web アプリ・定期ジョブ・永続データを1つのアプリ内で組み合わせられることです。

パターン: 管理画面 + 夜間バッチ

Section titled “パターン: 管理画面 + 夜間バッチ”

Web アプリで設定やデータを入力し、重い処理は夜間ジョブに任せる構成です。

slug: sales-tool
runtime: python-slim
command: "pip install --user -r requirements.txt && python app.py"
db:
mode: libsql
env:
PORT: "8080"
crons:
- name: nightly-aggregate
schedule: "0 2 * * *"
command: "python aggregate.py"
timeout: 300
  • 日中: 管理画面から売上データを入力
  • 深夜: ジョブが集計処理を実行し、レポートデータを更新
  • 翌朝: 管理画面で集計結果を閲覧

パターン: アップロード CSV の定期処理

Section titled “パターン: アップロード CSV の定期処理”

ユーザーが Web UI から CSV をアップロードし、ジョブが定期的に処理する構成です。

crons:
- name: process-csv
schedule: "*/30 * * * *"
command: "python process_inbox.py"
timeout: 180
  • Web アプリ: CSV を /data/inbox/ にアップロード
  • ジョブ(30分ごと): /data/inbox/ の未処理ファイルを処理し、結果を /data/outbox/ に保存
  • Web アプリ: 処理結果を一覧表示・ダウンロード

ジョブが毎朝データを要約し、Web アプリで閲覧する構成です。

crons:
- name: daily-summary
schedule: "0 7 * * *"
command: "python generate_summary.py"
timeout: 600
  • ジョブ(毎朝 7:00): 前日のデータを AI API で要約し、結果を SQLite に保存
  • Web アプリ: 要約を日付別に閲覧

cron 式のフィールド順(分・時・日・月・曜日)を間違えやすいです。「9時に実行したい」場合は 0 9 * * * です。9 0 * * * とすると毎日 0:09 に実行されます。

# NG — 毎日 0:09 に実行される
schedule: "9 0 * * *"
# OK — 毎日 9:00 に実行される
schedule: "0 9 * * *"

一時ファイルと永続データを混同する

Section titled “一時ファイルと永続データを混同する”

ローカルファイル(/tmp/data)に書いた出力は次回実行時には消えている場合があります(ワーカー / cron は Web と別コンテナで走り、ローカルディスクを共有しません)。結果を残したい場合はデータベース(db.mode: libsql)に保存してください。

ローカルでは動くが本番で認証情報が足りない

Section titled “ローカルでは動くが本番で認証情報が足りない”

外部 API を呼び出すジョブで、API キーをローカルの環境変数にだけ設定していると、Keelson 上では認証エラーになります。keelson.yamlenv またはダッシュボードで環境変数を設定してください。

外部 API のレート制限に引っかかる

Section titled “外部 API のレート制限に引っかかる”

毎分実行のジョブで外部 API を大量に呼ぶと、レート制限で失敗します。実行間隔を広げるか、ジョブ内でリクエスト数を制御してください。

Scheduled Jobs(cron の発火 + worker の tick の合算)にはプランごとに月間の実行回数上限があります(Starter: 1,000回 / Plus: 5,000回 / Team: 15,000回 / Business: 80,000回)。上限に達すると、当月の残りの実行はスキップされます。毎分実行(* * * * *)は月間約43,200回になるため、テスト以外では避けてください。


Web アプリなしで、ジョブだけを動かす最小構成です。

slug: my-cron
runtime: python-slim
env:
PYTHONUNBUFFERED: "1"
crons:
- name: heartbeat
schedule: "* * * * *"
command: "python heartbeat.py"
timeout: 30

heartbeat.py:

import datetime
print(f"OK: {datetime.datetime.now()}")

Python: 売上データを集計して保存する

Section titled “Python: 売上データを集計して保存する”
import os, json, datetime, libsql
conn = libsql.connect(
database=os.environ["KEELSON_DB_URL"],
auth_token=os.environ["KEELSON_DB_AUTH_TOKEN"],
)
today = datetime.date.today().isoformat()
row = conn.execute(
"SELECT COUNT(*), SUM(amount) FROM sales WHERE date = ?", (today,)
).fetchone()
report = {"date": today, "count": row[0], "total": row[1] or 0}
conn.execute(
"INSERT INTO reports (date, payload) VALUES (?, ?)",
(today, json.dumps(report, ensure_ascii=False)),
)
conn.commit()
print(f"集計完了: {report}")

Node.js: 外部 API からデータを同期する

Section titled “Node.js: 外部 API からデータを同期する”
import { createClient } from "@libsql/client";
const db = createClient({
url: process.env.KEELSON_DB_URL,
authToken: process.env.KEELSON_DB_AUTH_TOKEN,
});
const API_URL = process.env.SYNC_API_URL;
async function sync() {
const res = await fetch(API_URL);
const items = await res.json();
await db.execute(`
CREATE TABLE IF NOT EXISTS synced_items (
id TEXT PRIMARY KEY,
data TEXT,
synced_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
for (const item of items) {
await db.execute({
sql: `INSERT INTO synced_items (id, data) VALUES (?, ?)
ON CONFLICT(id) DO UPDATE SET data = excluded.data, synced_at = CURRENT_TIMESTAMP`,
args: [item.id, JSON.stringify(item)],
});
}
console.log(`同期完了: ${items.length} 件`);
}
sync().catch((err) => {
console.error("同期失敗:", err);
process.exit(1);
});
import os, json, urllib.request, datetime
SLACK_WEBHOOK = os.environ["SLACK_WEBHOOK_URL"]
message = {
"text": f"日次レポート準備完了: {datetime.date.today()}"
}
req = urllib.request.Request(
SLACK_WEBHOOK,
data=json.dumps(message).encode(),
headers={"Content-Type": "application/json"},
)
urllib.request.urlopen(req)
print("Slack 通知送信完了")

keelson.yaml:

slug: daily-notifier
runtime: python-slim
env:
PYTHONUNBUFFERED: "1"
SLACK_WEBHOOK_URL: "https://hooks.slack.com/services/..."
crons:
- name: daily-notify
schedule: "0 9 * * 1-5"
command: "python notify.py"
timeout: 30

ワーカー(バックグラウンドのドレイン処理)

Section titled “ワーカー(バックグラウンドのドレイン処理)”

「毎日9時」のような時刻ではなく、「溜まった仕事を数分おきに片付ける」間隔で動かしたい処理には、crons ではなく workers を使います。

ワーカーは**常駐プロセスではなく「定期ドレイン」**です。プラットフォームが every 間隔ごとにワーカーを起こし、command を 1 回実行し、溜まった仕事を処理し終えたら止めます。tick と tick の間はプロセスが動いていません(アプリはアイドル時にゼロにスケールします)。

slug: mailer
runtime: python-slim
command: "python app.py" # Web: 受け付けた仕事を pending 行として記録
env:
PYTHONUNBUFFERED: "1"
db:
mode: libsql # Web とワーカーで共有する永続ストア
workers:
- name: drain
command: "python worker.py" # pending 行を処理して exit 0
every: 10m
timeout: 2m

ワーカーを書くときの3つのルール

Section titled “ワーカーを書くときの3つのルール”

ワーカーは Web アプリとは別のコンテナで実行されます。Web アプリのメモリやディスク(/data)は共有しません。そのため次の作法で書いてください。

  1. 仕事は DB の pending 行にためて、冪等にドレインする — Web 側は仕事をデータベース(db.mode: libsql)に pending 行として書き込みます。ワーカーは pending 行を取り出して処理し、processed_at / status を更新(同じ行を二度処理しても無害になるように)して、キューが空になったら exit 0 します。tick は途中で kill されて再実行され得るため、各処理は何度実行しても安全に書きます。
  2. アプリ内スケジューラを使わない — APScheduler / node-cron / FastAPI BackgroundTasks / setInterval などをアプリのプロセスに埋め込まないでください。これらは存在しない「常駐プロセス」を前提にしており、アイドル時に動きません。定期処理は crons(時刻指定)か workers(間隔ドレイン)の宣言に移します。
  3. 触ってよい状態は DB とオブジェクトストレージだけ — ワーカーの durable な状態はデータベース(db.mode: libsql)またはオブジェクトストレージ API に置きます。ワーカーが /data などローカルパスに書いたファイルは破棄され、Web アプリからは見えません。
  • every(tick 間隔)の許容値は 5m / 10m / 15m / 20m / 30m / 60m、または 2h / 3h / 4h / 6h / 8h / 12h / 24h です。既定は 30m
  • timeout(1 tick の実行上限)は every の 1/5 以下です(例: every: 30m なら最大 6m)。既定は 5m で、短い間隔では自動的に切り下げられます。

cronsworkers の上限はプランによって異なります。

StarterPlusTeam
ワーカー本数 / app不可1本2本
ワーカー every 下限30分10分
cron 本数 / app3510
cron 最小間隔60分15分5分
実行 timeout 上限3分5分10分
Scheduled Jobs 回数 / 月1,0005,00015,000
  • ワーカーは Plus 以上で利用できます。Starter では crons(最短60分間隔・最大3本)で定期処理を組みます。
  • 「Scheduled Jobs 回数 / 月」は cron の発火と worker の tick の合算です。上限に達すると当月の残りはスキップされ、翌月にリセットされます。
  • Business プランの上限はこれより緩和されます(ワーカー3本 / app・every 下限5分・cron 10本・最小間隔5分・timeout 15分・80,000回 / 月)。

crons / workers の設定がプランや実行モデルに合わないと、デプロイは拒否されます。エラーには code と対処方法(hint)が含まれるので、そのまま AI エージェントに渡せば修正できます。

状況対処
ワーカーがこのプランで使えないPlus 以上へアップグレードするか、workers: 宣言を削除します。Starter の定期処理は crons で組みます
every が許容値でない5m / 10m / 15m / 20m / 30m / 60m または 2h / 3h / 4h / 6h / 8h / 12h / 24h のいずれかにします
timeoutevery の 1/5 を超えているtimeout を下げるか every を長くします(例: every: 30m なら timeout ≤ 6m
replicas / resources を指定しているどちらもワーカーには指定できません。削除します(CPU / メモリはアプリ単位の設定です)
本数・間隔・timeout がプラン上限を超えている上記のプラン制限表に収めるか、上位プランへアップグレードします

定期実行ジョブが向いているケース

Section titled “定期実行ジョブが向いているケース”
  • 定型業務の自動化 — 毎日・毎時間の集計、通知、データ同期
  • Web アプリと組み合わせた業務フロー — 日中は入力、夜間にバッチ処理
  • 外部サービスとの定期的なデータ連携 — API からの取得や Webhook 送信
  • 社内データの定期メンテナンス — 古いデータの削除、レポート生成
  • リアルタイム処理 — イベント駆動で即座に反応する必要がある場合は、Web アプリ内で処理してください
  • 1時間を超える長時間処理 — タイムアウトの上限は 3,600 秒です
  • 複雑なジョブチェーン — ジョブ間の依存関係やワークフロー制御が必要な場合は、専用のワークフローエンジンを検討してください
  • 秒単位の精度が必要 — cron 式は分単位の指定です

ジョブが失敗したら自動でリトライされますか?

Section titled “ジョブが失敗したら自動でリトライされますか?”

されません。次のスケジュールで再実行されます。ジョブを冪等に設計しておけば、自然にリカバリされます。

Web アプリなしでジョブだけ動かせますか?

Section titled “Web アプリなしでジョブだけ動かせますか?”

はい。keelson.yamlcommand を省略し、crons だけを定義すれば、ジョブ専用のアプリとしてデプロイできます。

ジョブの実行結果をどこで確認できますか?

Section titled “ジョブの実行結果をどこで確認できますか?”

ダッシュボードから、ジョブごとの実行履歴・成功/失敗のステータス・ログを確認できます。

月間実行回数の上限に達したらどうなりますか?

Section titled “月間実行回数の上限に達したらどうなりますか?”

当月の残りの実行はスキップされます。翌月にリセットされます。上限はプランによって異なります(Starter: 1,000回 / Plus: 5,000回 / Team: 15,000回 / Business: 80,000回)。cron の発火と worker の tick の合算でカウントされます。

タイムゾーンはどうなっていますか?

Section titled “タイムゾーンはどうなっていますか?”

cron / worker のスケジュールは Asia/Tokyo(日本時間)で評価されます。


「毎朝9時に売上データを集計するジョブを追加してください。keelson.yaml の crons に定義してください」

「30分ごとに外部 API からデータを取得して SQLite に同期するバッチ処理を作ってください」

「このアプリに、毎日深夜3時に古いデータを削除するクリーンアップジョブを追加してください」

keelson.yaml の設定

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

keelson.yaml は、Keelson がアプリをどのようにビルドし、起動し、公開するかを判断するための設定ファイルです。

このページでは、keelson.yaml が何のためにあるのか、何を書けばよいのか、どう使われるのかを説明します。各フィールドの完全な定義については keelson.yaml リファレンス を参照してください。

ただし、keelson.yaml は Keelson の Agent Skill 機能を使えば AI エージェントが自動生成してくれるため、通常は自分で作成する必要はありません。

keelson.yaml は、アプリごとに用意する設定ファイルです。プロジェクトのルートディレクトリに配置します。

Keelson はこのファイルを読み取り、次のことを判断します。

  • アプリの識別子(URL の一部になる)
  • どのランタイムで動かすか
  • どのように起動するか
  • 永続ストレージやデータベースを使うか
  • 定期実行ジョブやバックグラウンドワーカーがあるか
  • 静的アセット配信を行うか

keelson.yaml は、アプリのコードそのものではなく、そのアプリを Keelson 上で動かすための説明書です。すべての設定項目を覚える必要はなく、まずは最小限の構成から始められます。

同じ Web アプリでも、使用する言語、起動コマンド、必要な機能はアプリごとに異なります。

Keelson は keelson.yaml を通じてその違いを理解し、適切な方法でアプリをデプロイします。このファイルがないと、Keelson はそのアプリをどう扱えばよいか判断できません。

AI エージェントでデプロイする場合も、keelson.yaml はアプリの構成を理解するための重要な手がかりになります。エージェントがアプリのコードを読み取って keelson.yaml を自動生成することもできます。

keelson.yaml は、デプロイの開始時に読み取られます。

Keelson はこの設定をもとに、次の処理を行います。

  1. 設定の検証 — フィールドの値やフィールド間の制約をチェックする
  2. ビルド — ランタイムに応じたコンテナイメージを作成する
  3. 起動command で指定されたコマンドでアプリを開始する
  4. 機能の有効化 — ストレージ、データベース、定期実行ジョブなど、設定された機能を準備する
  5. 公開slug に基づいた URL でアプリにアクセスできるようにする

設定がアプリの実際の構成と合っていない場合、ビルドに失敗したり、ビルドは成功しても起動できなかったりすることがあります。

keelson.yaml のフィールドはすべてトップレベルに配置します。

フィールド説明
slugアプリの識別子。URL の一部になるmy-app
runtime実行環境python-slim, node-slim, go-slim
command起動コマンド"python app.py"

command は、依存パッケージのインストールと起動を 1 つのコマンドにまとめて書きます。

command: "python -m pip install -r requirements.txt && python app.py"
フィールド説明
env環境変数(キーと値のペア)
storage永続ストレージの設定
databasesSQLite データベースの設定
crons定期実行ジョブ
workersバックグラウンドワーカー
assets静的アセット配信
typeアプリ種別(web を指定すると静的サイトモード)

各フィールドの型、制約、指定可能な値については keelson.yaml リファレンス を参照してください。

commandassets の組み合わせによって、デプロイモードが自動的に決まります。

パターンcommandassets動作
通常のアプリありなしコンテナとして起動
静的サイト / SPAなしあり静的ファイルを配信
ハイブリッドありあり静的ファイル + バックエンド API

API キー、トークン、パスワードなどの秘密情報は keelson.yaml に直接書かないでください。

keelson.yaml はソースコードと一緒にリポジトリに含まれるファイルです。秘密情報は環境変数またはシークレットとして、コンソールから設定します。

# NG: 秘密情報を直接書いている
env:
OPENAI_API_KEY: "sk-xxxxxxxxxxxxx"
# OK: 値はコンソールで設定し、keelson.yaml には書かない
env:
PORT: "8080"
NODE_ENV: "production"

環境変数の管理については 環境変数とシークレット を参照してください。

まずは slugruntimecommand の 3 つだけで始められます。

slug: my-app
runtime: python-slim
command: "python -m pip install -r requirements.txt && python app.py"
env:
PORT: "8080"
slug: my-app
runtime: node-slim
command: "npm install && npm start"
env:
PORT: "8080"
slug: my-app
runtime: go-slim
# Keelson が deploy 時に Linux 向け binary を `./app` としてビルドします。
command: "./app"
env:
PORT: "8080"

ランタイムには -slim(軽量)と -media(画像・動画処理ライブラリ含む)の 2 種類があります。迷った場合は -slim から始めてください。

アプリの種類によって、使うフィールドが変わります。

Web アプリ + Managed SQLite(libSQL)

Section titled “Web アプリ + Managed SQLite(libSQL)”

データベースを使うアプリでは、db.mode: libsql を宣言します。接続情報(KEELSON_DB_URL / KEELSON_DB_AUTH_TOKEN)が環境変数で注入されます。

slug: my-app
runtime: python-slim
command: "python -m pip install -r requirements.txt && python app.py"
db:
mode: libsql
env:
PORT: "8080"

/data は揮発(一時領域)で永続化されません。永続データは Managed SQLite(libSQL)に置いてください。

type: web を指定し、assets でアセットディレクトリを設定します。

slug: my-site
type: web
runtime: node-slim
assets:
dir: dist
fallback: index.html

Web サーバーなしで、定期的にスクリプトを実行するだけのアプリです。

slug: daily-report
runtime: python-slim
crons:
- name: generate
schedule: "0 9 * * *"
command: "python report.py"
timeout: 120

ハイブリッド(静的ファイル + API)

Section titled “ハイブリッド(静的ファイル + API)”

フロントエンドの静的ファイルとバックエンド API を 1 つのアプリで提供します。

slug: my-app
runtime: node-slim
command: "npm install && node server.js"
env:
PORT: "8080"
assets:
dir: public
fallback: index.html
api: /api

各構成パターンの完全な例は keelson.yaml リファレンス を参照してください。

アプリからファイルをダウンロードする

Keelson CLI から、稼働中のアプリの /data にあるファイルを配置・取得・一覧・削除する機能は 提供していません。

ユーザーがアプリの生成物を取り出す必要がある場合は、アプリ自身に download endpoint を実装してください。 endpoint はアプリが管理するデータソースから対象データを読み、適切な Content-TypeContent-Disposition: attachment を付けてレスポンスを返します。通常のアプリ route には Keelson の 認証ゲートが適用されます。

永続化する構造化データには Keelson Managed SQLite を使い、バイナリなどを外部 object storage に 保存する場合はアプリからそのサービスへ接続します。ローカルファイルだけを正本にしないでください。

永続ストアからの読み取り専用取得と Console からのダウンロードは、ローンチ後の backlog です。

デプロイと設定


デプロイする

このページでは、あなたが作ったアプリをKeelsonにデプロイする方法を説明します。クイックスタートでサンプルアプリを試した方が、自分のアプリを載せるときに読むことを想定しています。

Keelsonにおけるデプロイとは、コードを渡して終わりではありません。アプリがビルドされ、起動し、アプリURLでアクセスできる状態になるまでを指します。

デプロイは次の流れで進みます。

  1. アプリを用意する — ソースコードが手元にある状態にする
  2. keelson.yaml を作成する — Keelsonにアプリの動かし方を伝える設定ファイルを置く
  3. AIエージェントにデプロイを依頼する — Agent Skillを使ってデプロイを実行する
  4. Keelsonがビルド・起動・確認を行う — コンテナイメージのビルド、コンテナ起動、ヘルスチェックが自動で走る
  5. アプリURLで利用できるようになるhttps://<slug>.keelson.run でアプリにアクセスできる

デプロイを始める前に、以下を確認してください。

  • アプリのソースコードがある
  • 対応しているランタイムでアプリが動く
  • keelson.yaml がプロジェクトのルートに置いてある
  • 必要な環境変数やシークレットを把握している(→ 環境変数とシークレット
  • Keelson CLIがインストールされ、ログイン済みである
  • Agent Skillがインストールされている

keelson.yaml は、Keelsonがアプリをどう動かすかを判断するための設定ファイルです。プロジェクトのルートディレクトリに配置します。

このファイルには、アプリの識別子、使用するランタイム、起動コマンドなど、デプロイに必要な情報を記述します。

最小構成の例:

slug: my-app
runtime: python-slim
command: "python app.py"
  • slug — アプリの識別子。アプリURLの一部になります(my-app.keelson.run
  • runtime — 実行環境。python-slimnode-slimgo-slim など
  • command — アプリの起動コマンド

これ以外にも、環境変数、データベース、定期実行ジョブなどのフィールドがあります。全項目の詳細は keelson.yaml リファレンス を参照してください。

AIエージェントにデプロイを依頼する

Section titled “AIエージェントにデプロイを依頼する”

対象のアプリフォルダをAIエージェント(Claude Code、Codexなど)で開いた状態で、デプロイを依頼します。

依頼の例:

「このアプリをKeelsonにデプロイして」

「keelson.yaml がなければ作成してから、Keelsonにデプロイして」

「起動エラーが出たら原因を調べて修正し、再デプロイして」

AIエージェントは keelson.yaml を読み取り、ビルドとデプロイを自動で実行します。keelson.yaml がない場合は、アプリの構成を判断して作成することもできます。

デプロイを実行すると、Keelsonは以下の処理を順に行います。

  1. 設定の確認keelson.yaml の内容を検証する
  2. ビルド — ソースコードからコンテナイメージを作成する
  3. 起動 — コンテナを起動し、アプリのプロセスを開始する
  4. ヘルスチェック — アプリが正常にリクエストを受け付けるか確認する
  5. アプリURLの発行https://<slug>.keelson.run でアクセス可能になる

ユーザーがこれらの手順を個別に操作する必要はありません。AIエージェントが進行状況を確認しながら完了まで進めます。

デプロイが成功したとは、次の状態を指します。

  • アプリのコンテナが起動している
  • ヘルスチェックに通過している
  • アプリURLでアクセスできる

ビルドが通っただけでは完了ではありません。起動して、URLで正常に開ける状態が「デプロイ成功」です。

デプロイに失敗した場合、AIエージェントはビルドログやランタイムログを確認して原因を調査できます。設定ミスや起動エラーがあれば、修正して再デプロイします。

まずはエラーメッセージを確認し、必要に応じてAIエージェントに修正を依頼してください。

原因対処
keelson.yaml の不足や記述ミスファイルの有無と内容を確認する
起動コマンドの不一致command がアプリの実際のエントリポイントと合っているか確認する
必要な環境変数が未設定コンソールまたは keelson.yamlenv で設定する
アプリが期待するポートで起動していないアプリがポート 8080 でリッスンしているか確認する
ビルドは通るが実行時エラーで落ちるランタイムログを確認し、依存関係や設定の不備を調べる

環境変数とシークレット

アプリが外部サービスと連携するには、APIキーや接続情報が必要です。これらの値をコードに直接書くのではなく、環境変数として管理することで、安全かつ柔軟に設定を切り替えられます。

このページでは、Keelsonで環境変数とシークレットを設定・管理する方法を説明します。

Keelsonでは、環境変数を2つの方法で設定できます。

keelson.yamlenv フィールドに記述した値は、ビルド時と実行時の両方で利用できます。

slug: my-app
runtime: python-slim
command: "python app.py"
env:
PORT: "8080"
NODE_ENV: "production"

秘密にする必要のない設定値(ポート番号、動作モードなど)はここに書きます。

コンソールでシークレットとして設定する

Section titled “コンソールでシークレットとして設定する”

APIキーやアクセストークンなどの機密情報は、コンソールからシークレットとして設定します。シークレットは暗号化されてデータベースに保存され、実行時にアプリへ注入されます。

シークレットの値はコンソール上で再表示されません。キー名と最終更新日時のみ確認できます。

シークレットは、ワークスペース単位とアプリ単位の2つのスコープで設定できます。

コンソールの シークレット ページで設定します。ワークスペース内のすべてのアプリから参照できます。

複数のアプリで共通して使う値(共有APIキーなど)に適しています。

コンソールのアプリ詳細画面で設定します。そのアプリだけに適用されます。

特定のアプリだけ別の値を使いたい場合や、ワークスペースシークレットを上書きしたい場合に使います。

同じキー名の環境変数が複数の場所で設定されている場合、次の順で優先されます。

優先度設定場所説明
アプリシークレットそのアプリだけに適用される
ワークスペースシークレットワークスペース全体に適用される
keelson.yaml の envソースコードに含まれる静的な値

たとえば、ワークスペースシークレットに API_KEY を設定し、特定のアプリだけ別の API_KEY を使いたい場合は、そのアプリにアプリシークレットとして設定すれば上書きできます。

keelson.yamlenv も同様に、変更後は再デプロイで反映されます。

タイミングkeelson.yaml の envシークレット
ビルド時利用できる利用できない
実行時利用できる利用できる

フロントエンドのビルドで環境変数が必要な場合(例: VITE_API_URL)は、keelson.yamlenv に記述してください。シークレットはビルドプロセスには渡されません。

シークレットと keelson.yamlenv は、どちらも通常の環境変数としてアプリから参照できます。

Python:

import os
api_key = os.environ["API_KEY"]

Node.js:

const apiKey = process.env.API_KEY;

Go:

apiKey := os.Getenv("API_KEY")

シークレットとして管理すべき値

Section titled “シークレットとして管理すべき値”

以下のような値は、keelson.yaml ではなくコンソールのシークレットとして設定してください。

  • APIキー・アクセストークン
  • OAuth クライアントシークレット
  • データベース接続文字列
  • 外部サービスの認証情報
  • Webhook のシークレットキー

システムが自動設定する環境変数

Section titled “システムが自動設定する環境変数”

Keelsonは、以下の環境変数を自動的にアプリに設定します。ユーザーが同じキー名で値を設定する必要はありません。

変数名内容
TZタイムゾーン
KEELSON_APP_IDアプリの識別子
KEELSON_TENANT_IDワークスペースの識別子

アプリURL

デプロイが完了すると、Keelsonはアプリに専用のURLを自動で発行します。このページでは、そのURLがどう決まり、どのような性質を持つかを説明します。

アプリURLは次の形式で発行されます。

https://{ワークスペースslug}--{アプリslug}.keelson.run

たとえば、ワークスペースのslugが acme、アプリのslugが dashboard の場合:

https://acme--dashboard.keelson.run

アプリのslugは keelson.yamlslug フィールドで指定した値が使われます。

アプリURLは以下の場所で確認できます。

  • コンソール — アプリ詳細画面にURLが表示されます
  • デプロイ完了時 — AIエージェントがデプロイ結果としてURLを通知します

URLをコピーして、チームメンバーに共有できます。

アプリURLへのアクセスは、権限が付与されたユーザーのみに制限されます。すべての接続はHTTPSで暗号化されており、証明書の取得や更新をユーザーが行う必要はありません。

アクセス制御の詳細は以下を参照してください。

カスタムドメイン

Keelson では、デプロイしたアプリに独自のサブドメインを割り当てられるようにする予定です。

通常、アプリには Keelson が発行する公開 URL が割り当てられます。カスタムドメインを使うと、app.example.com のような自社のサブドメインでアプリを公開できるようになります。

  • 対象プラン: Team プラン
  • 割り当て可能数: テナント合計で最大 10 件(1 アプリにつき 1 ドメイン)
  • 対応するドメイン: サブドメイン(app.example.com)のみ。ルートドメイン(apex, example.com)とメールドメインは対象外です。
  • 社内ツールを自社ドメイン配下で公開したい
  • ユーザーに Keelson の標準 URL ではなく、わかりやすい URL を案内したい
  • 既存の社内ポータルや社内サイトと URL を揃えたい

Keelson では、デプロイに成功すると標準の公開 URL が発行されます。 カスタムドメインは、その標準 URL に加えて、独自のサブドメインでも同じアプリへアクセスできるようにする機能です。

カスタムドメインを設定しても、アクセス制御のルールは変わりません。 認証や IP 制御を有効にしている場合は、カスタムドメイン経由のアクセスにも同じ制限が適用されます。

設定の流れ(提供開始時に案内します)

Section titled “設定の流れ(提供開始時に案内します)”

具体的な設定手順(DNS レコードの追加内容、確認方法、TLS 証明書の扱いなど)は、機能の提供開始に合わせて本ページで案内します。

IP制御

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson では、アプリにアクセスできる送信元 IP アドレスを制限できます。

IP 制御を使うと、特定のオフィス、VPN、社内ネットワークなど、許可したネットワークからのアクセスだけを受け付けることができます。 認証とあわせて使うことで、社内アプリをより安全に公開できます。

  • 社内ネットワークや VPN からのアクセスだけを許可したい
  • 認証に加えて、ネットワーク単位でもアクセスを制限したい
  • URL を知っているだけではアクセスできないようにしたい

IP 制御を有効にすると、許可リストに含まれる IP アドレスまたは IP 範囲からのアクセスだけが許可されます。

許可されていない IP アドレスからアクセスした場合、認証画面を含め、アプリには一切アクセスできません。 正しいアカウントを持っていても、許可されたネットワーク外からはアクセスできません。

つまり、IP 制御は認証の代わりではなく、認証に追加するネットワーク制限です。

  1. Keelson のコンソールで対象アプリを開きます
  2. IP 制御の設定画面を開きます
  3. 許可する IP アドレスまたは IP 範囲を追加します
  4. 設定を保存します
  5. 許可されたネットワークと、許可されていないネットワークの両方から動作を確認します

IP 制御では、通常は次の形式で IP アドレスを指定します。

  • 単一の IP アドレス 例: 203.0.113.10
  • CIDR 形式の IP 範囲 例: 203.0.113.0/24
  • 203.0.113.10 特定の 1 台だけを許可する例です
  • 203.0.113.0/24 203.0.113.x の範囲をまとめて許可する例です

CIDR の意味がわからない場合は、ネットワーク管理者に確認してください。 オフィスや VPN の固定グローバル IP を登録するケースが一般的です。

IP 制御と認証は独立した仕組みですが、IP 制御が先に評価されます。 許可されていないネットワークからは、認証画面にも到達しません。

より安全に運用したい場合は、次の組み合わせをおすすめします。

  • 認証を有効にする
  • 必要なメンバーだけにアプリ権限を付与する
  • 必要に応じて IP 制御を有効にする

アクセス制御


認証とログイン

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson にデプロイされたアプリは、すべて認証が必要です。 アプリの URL を知っているだけではアクセスできず、ログインしたうえで、そのアプリへの権限を持つユーザーだけが利用できます。

このページでは、Keelson における認証の仕組みとログインの流れを説明します。

Keelson では、アプリの前段に認証プロキシが配置されています。 ユーザーのリクエストは必ずこのプロキシを経由し、認証と権限の確認が行われたうえでアプリに到達します。

この仕組みにより、アプリのコードに認証ロジックを書く必要はありません。 どの言語・フレームワークで作ったアプリでも、デプロイするだけで認証つきの状態になります。 AI ツールで生成したアプリをそのまま載せても、認証なしで外部に公開されることはありません。

Keelson では、次のアカウントでログインできます。

  • Google アカウント
  • Microsoft アカウント

ワークスペースのメンバーとして登録されているユーザーだけがログインできます。 ワークスペースに参加していないユーザーは、正しいアカウントを持っていてもアプリにアクセスできません。

メンバーの追加方法については、メンバーとアプリ権限 を参照してください。

  1. ユーザーがアプリの URL にアクセスします
  2. ログインしていない場合、ログイン画面に移動します
  3. Google または Microsoft アカウントで認証します
  4. ログイン後、元のアプリに戻ります
  5. そのアプリへの権限がある場合、アプリが表示されます
  6. 権限がない場合、アクセスが拒否されます

ログイン状態は一定期間保持されます。有効期間中は、同じワークスペース内の他のアプリにもログインなしでアクセスできます。

ログインできることと、アプリを使えることは同じではありません。

Keelson では、次の順序でアクセスが判断されます。

  1. ログインしているか — ユーザーが認証済みかどうか
  2. アプリへの権限があるか — そのユーザーが対象アプリのメンバーかどうか
  3. ネットワーク条件を満たしているか — IP 制御が設定されている場合、許可された IP アドレスからのアクセスかどうか

ログインに成功しても、対象アプリへの権限がなければ利用できません。

アプリから認証情報を利用する

Section titled “アプリから認証情報を利用する”

認証済みのリクエストには、認証プロキシがユーザー情報をヘッダーとして付与します。

アプリのコード内で X-Keelson-User-Id ヘッダーを読み取ることで、現在のログインユーザーを識別できます。

# Python (Flask / FastAPI など)
user_id = request.headers.get("X-Keelson-User-Id")
// Node.js (Express など)
const userId = req.headers["x-keelson-user-id"];

認証ヘッダーや Cookie は、プロキシがアプリ到達前に除去します。 アプリが受け取るのは Keelson が付与したヘッダーだけです。

認証は「誰がアクセスするか」を制御します。 IP 制御は「どのネットワークからアクセスするか」を制御します。

IP 制御を設定している場合、許可されていないネットワークからはログイン画面にも到達しません。 認証と IP 制御は独立した仕組みですが、組み合わせることでより安全に運用できます。

IP 制御について詳しくは IP制御 を参照してください。

メンバーとアプリ権限

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson では、アプリへのアクセスをワークスペース単位で制御します。 ワークスペースのメンバーになっているユーザーは、そのワークスペース内のすべてのアプリにアクセスできます。

このページでは、メンバーの管理方法、ロールの違い、参加方法について説明します。

Keelson のアクセス制御は、ワークスペースへの所属で決まります。

  • ワークスペースに参加しているメンバーは、そのワークスペースのアプリすべてにアクセスできる
  • ワークスペースに参加していないユーザーは、どのアプリにもアクセスできない

ログインの仕組みについては 認証とログイン を参照してください。

ワークスペースのメンバーには、4 種類のロールがあります。

ロールコンソールアプリ利用メンバー管理
Ownerすべての機能すべてのロールを管理できる
Adminすべての機能Owner 以外を管理できる
Builder読み取りのみ不可
App Userアクセス不可不可

ワークスペースの全権限を持ちます。メンバーの追加・削除、ロールの変更、アプリの管理など、すべての操作が可能です。 ワークスペースには最低 1 人の Owner が必要です。

Owner とほぼ同等の権限を持ちますが、Owner ロールのメンバーを管理することはできません。 チームの管理者に適したロールです。

コンソールを閲覧できますが、メンバー管理などの変更操作はできません。 アプリの開発・デプロイを行うメンバーに適したロールです。

デプロイされたアプリを利用できますが、コンソールにはアクセスできません。 アプリのエンドユーザーに適したロールです。開発者枠を消費しません。

ワークスペースにメンバーが参加する方法は 3 つあります。

管理者がメールアドレスを指定してメンバーを招待します。 招待時にロールを指定でき、招待されたユーザーがリンクを承認するとメンバーになります。

招待の操作方法については メンバーを招待する を参照してください。

企業のメールドメインを登録すると、そのドメインのメールアドレスを持つユーザーが自動的にワークスペースに参加できます。

  • DNS TXT レコードによるドメインの所有権確認が必要です
  • 自動参加したメンバーには App User ロールが付与されます
  • Gmail や Outlook など、パブリックなメールドメインでは利用できません
  • 1 つのドメインにつき、自動参加を設定できるワークスペースは 1 つだけです

社内メンバーを一括でオンボーディングしたい場合に便利です。

企業のメールドメインに対して承認制ポリシーを設定すると、ユーザーが参加をリクエストし、管理者が承認する形でメンバーになれます。

  • ユーザーがアプリにアクセスすると、参加リクエストが作成されます
  • Owner または Admin がリクエストを承認すると、App User としてメンバーになります
  • 承認されるまでアプリにはアクセスできません

自動参加ほどオープンにしたくないが、招待の手間を減らしたい場合に適しています。

ドメインごとの参加ポリシーは、コンソールから設定できます。

ポリシー動作ドメイン検証
招待のみ(デフォルト)招待されたユーザーだけが参加できる不要
自動参加対象ドメインのユーザーが自動で参加できる必要(DNS TXT)
承認制参加リクエスト → 管理者承認で参加できる必要(DNS TXT)

ドメインポリシーを変更しても、既存メンバーのステータスには影響しません。

不要になったメンバーは、コンソールからブロックできます。

  • ブロックされたメンバーは、ワークスペース内のすべてのアプリにアクセスできなくなります
  • アカウントの削除ではなく、アクセス権の無効化です
  • 最後の Owner をブロックすることはできません
  • 自分自身をブロックすることはできません

退職者や異動メンバーのアクセスを停止する場合に使います。

アクセスできないときの確認ポイント

Section titled “アクセスできないときの確認ポイント”

ワークスペースに参加しているか

Section titled “ワークスペースに参加しているか”

ワークスペースのメンバーになっていないユーザーはアプリにアクセスできません。管理者に招待を依頼してください。

メンバーがブロックされていないか

Section titled “メンバーがブロックされていないか”

以前は参加していたが、ブロックされている可能性があります。コンソールのメンバー一覧で確認してください。

正しいアカウントでログインしているか

Section titled “正しいアカウントでログインしているか”

複数の Google / Microsoft アカウントを使い分けている場合、ワークスペースに登録されていないアカウントでログインしている可能性があります。

承認制のワークスペースでは、管理者が参加リクエストを承認するまでアクセスできません。

IP 制御でブロックされていないか

Section titled “IP 制御でブロックされていないか”

メンバーシップの問題ではなく、ネットワークの制限でアクセスできない場合があります。

ワークスペースに参加すればすべてのアプリを使えますか?

Section titled “ワークスペースに参加すればすべてのアプリを使えますか?”

はい。現在、アクセス制御はワークスペース単位です。メンバーはワークスペース内のすべてのアプリにアクセスできます。

App User と Builder の違いは何ですか?

Section titled “App User と Builder の違いは何ですか?”

App User はデプロイされたアプリだけを利用できます。Builder はコンソールの閲覧もできますが、メンバー管理などの変更操作はできません。

自動参加したメンバーのロールを変更できますか?

Section titled “自動参加したメンバーのロールを変更できますか?”

はい。自動参加時は App User ロールが付与されますが、Owner または Admin がコンソールからロールを変更できます。

メンバーをブロックするとどうなりますか?

Section titled “メンバーをブロックするとどうなりますか?”

そのメンバーはワークスペース内のすべてのアプリにアクセスできなくなります。ブロックは即時反映されます。

ワークスペース管理


メンバーを招待する

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

ワークスペースにメンバーを招待すると、そのユーザーはログインしてワークスペース内のすべてのアプリを利用できるようになります。

このページでは、招待の操作手順、ロールの選び方、招待の管理方法を説明します。

  1. コンソールでワークスペースのメンバー管理画面を開きます
  2. 「招待」を選択します
  3. 招待するユーザーのメールアドレスを入力します
  4. ロールを選択します
  5. 有効期限を設定します
  6. 招待を送信します

招待が送信されると、一意のリンクつきメールが届きます。 招待されたユーザーがリンクを開いて承認すると、ワークスペースのメンバーになります。

招待時に、そのメンバーに付与するロールを選択します。

ロール用途開発者枠
Ownerワークスペース全体の管理者消費する
Adminメンバー管理・アプリ管理の担当者消費する
Builderアプリの開発・デプロイを行う担当者消費する
App Userデプロイされたアプリを利用するエンドユーザー消費しない

各ロールの詳細については メンバーとアプリ権限 を参照してください。

誰がどのロールで招待できるか

Section titled “誰がどのロールで招待できるか”
  • Owner は、すべてのロール(Owner を含む)でメンバーを招待できます
  • Admin は、Admin・Builder・App User で招待できます(Owner への招待はできません)
  • BuilderApp User は招待できません

Owner、Admin、Builder ロールでの招待は、プランごとの開発者枠を消費します。 枠が上限に達している場合、これらのロールでは招待できません。

App User は開発者枠を消費しないため、枠の上限に関係なく招待できます。

枠が足りない場合は、プランのアップグレードを検討するか、不要な開発者ロールのメンバーを App User に変更してください。

招待には次の 4 つの状態があります。

状態説明
Pending送信済み、未承認
Acceptedユーザーが承認し、メンバーとして参加済み
Revoked管理者が取り消し済み
Expired有効期限切れ

コンソールのメンバー管理画面から、招待の状態を確認できます。

Pending 状態の招待は、Owner または Admin が取り消せます。 取り消された招待のリンクは無効になります。

期限切れや取り消し済みの招待に対しては、同じメールアドレスで新しい招待を作成してください。

招待を受け取ったユーザーの操作

Section titled “招待を受け取ったユーザーの操作”
  1. 招待メールに記載されたリンクを開きます
  2. Google または Microsoft アカウントでログインします
  3. 招待を承認します
  4. ワークスペースのメンバーになり、アプリにアクセスできるようになります

招待のほかに、ドメインポリシーを使った参加方法があります。

  • ドメイン自動参加 — 企業ドメインのユーザーが自動でメンバーになる
  • 承認制 — ユーザーが参加リクエストを送り、管理者が承認する

これらの設定方法については メンバーとアプリ権限 を参照してください。

うまくいかないときの確認ポイント

Section titled “うまくいかないときの確認ポイント”
  • 招待権限があるか — 招待できるのは Owner と Admin のみです
  • メールアドレスが正しいか — 入力内容を確認してください
  • すでに参加済みではないか — メンバー一覧で対象ユーザーを確認してください
  • 開発者枠が足りているか — Owner / Admin / Builder ロールで招待する場合、枠の上限を確認してください
  • 迷惑メールフォルダに入っていないか確認してください
  • 会社のメールフィルタでブロックされていないか確認してください
  • メールアドレスに誤りがないか確認してください
  • 必要に応じて招待を取り消し、正しいアドレスで再送してください
  • 招待メールと同じアドレスでログインしているか — 別のアカウントでは承認できません
  • 招待が期限切れになっていないか — 期限切れの場合は再送が必要です
  • 招待が取り消されていないか — 管理者に確認してください

参加後にアプリにアクセスできない

Section titled “参加後にアプリにアクセスできない”
  • 正しいアカウントでログインしているか — 複数アカウントを使い分けている場合に注意してください
  • IP 制御でブロックされていないか — 許可されたネットワークからアクセスしているか確認してください

招待すればその人はすべてのアプリを使えますか?

Section titled “招待すればその人はすべてのアプリを使えますか?”

はい。ワークスペースに参加したメンバーは、そのワークスペース内のすべてのアプリにアクセスできます。

招待に有効期限はありますか?

Section titled “招待に有効期限はありますか?”

はい。招待時に設定した有効期限を過ぎると、その招待は無効になります。必要に応じて新しい招待を送信してください。

招待後にロールを変更できますか?

Section titled “招待後にロールを変更できますか?”

はい。メンバーが参加した後でも、Owner または Admin がコンソールからロールを変更できます。

一度に複数人を招待できますか?

Section titled “一度に複数人を招待できますか?”

招待は 1 人ずつ送信します。

リファレンス


Keelson Deploy Spec

Spec version: 2025-03-14 / Raw text (AI向け): /ja/docs/reference/deploy-spec.txt

この文書は、Keelson にアプリをデプロイする際の対応ランタイム・制約・成立条件を定義する正本です。デプロイの可否判断は、この文書に従ってください。

クイックスタートや操作手順は デプロイする を参照してください。


Keelson におけるデプロイ成功とは、ビルドが完了することではありません。次の条件をすべて満たした場合にのみ、デプロイは成功とみなされます。

  1. アプリのビルドが完了している
  2. アプリのプロセスが起動している
  3. ヘルスチェックに通過している
  4. アプリ URL(https://<slug>.keelson.run)が発行されている
  5. アプリ URL にアクセスできる状態である

ビルドが成功しても、起動に失敗した場合やヘルスチェックに通らない場合は、デプロイ成功ではありません。


すべてのデプロイには keelson.yaml が必要です。プロジェクトのルートディレクトリに配置します。

最小構成:

slug: my-app
runtime: python-slim
command: "pip install --user -r requirements.txt && python app.py"
env:
PORT: "8080"

各フィールドの詳細は keelson.yaml リファレンス を参照してください。


Keelson は、以下のランタイム上でのみアプリを実行できます。

ランタイム言語用途
python-slimPython軽量。API、テキスト処理、自動化など
python-mediaPythonメディア処理向け。画像・動画ライブラリを含む
node-slimNode.js軽量。Web アプリ、API など
node-mediaNode.jsメディア処理向け。画像処理ライブラリを含む
go-slimGo軽量
go-mediaGoメディア処理向け

keelson.yamlruntime フィールドで指定します。迷った場合は -slim から始め、メディア処理系ライブラリが必要になったら -media に切り替えてください。

  • slim — 言語ランタイムと標準ライブラリのみ。ビルドが速く、イメージサイズが小さい
  • media — slim に加え、画像処理(Pillow、sharp 等)や動画処理に必要なシステムライブラリがプリインストールされている

特定のフレームワークに依存しません。command で起動でき、HTTP サーバーとしてリクエストを受け付けるアプリであれば動作します。

例: FastAPI、Flask、Express、Next.js、Hono、Gin など。


以下の言語・ランタイムはサポート対象外です。

  • Ruby
  • Java / Kotlin / Scala
  • PHP
  • Rust
  • .NET / C#
  • Elixir / Erlang
  • Swift

非対応ランタイムのアプリは、修正や変換を行っても Keelson へデプロイできません。


Keelson は固定されたビルド環境・実行環境を提供します。アプリはその環境上でビルドおよび起動できる必要があります。

  • OS: Linux
  • CPU: x86_64 (amd64)

アプリは非 root ユーザーとして実行されます。sudoapt-get install、システムレベルの変更は実行できません。

使用できません。Keelson はランタイムを選択し、command で起動する方式です。Dockerfile の代わりに keelson.yaml でランタイムと起動コマンドを指定します。

パス書き込み永続化用途
/data可(一時的)不可スクラッチ領域(エフェメラル)
アプリディレクトリ可(一時的)不可ソースコード、依存関係
/tmp可(一時的)不可一時ファイル
その他不可
  • ローカルファイルへの書き込みはすべてエフェメラルで、再起動・scale-to-zero で失われます
  • 永続的な関係データは Managed SQLite(db.mode: libsql)を使ってください(/data のファイル SQLite は永続化されません)
  • 一般ファイルの永続 I/O は keelson.yaml では設定できません。データファイル SDK を後続タスクで提供予定です
  • Web アプリは環境変数 PORT で指定したポートで HTTP リクエストを待ち受けてください
  • 0.0.0.0 で listen する必要があります。127.0.0.1localhost ではリクエストが届きません
  • HTTPS 終端は Keelson が行います。アプリは HTTP で listen してください

Keelson は任意の OS パッケージ追加を前提とした環境ではありません。

  • -slim ランタイムには最小限のシステムライブラリのみ含まれます
  • -media ランタイムには画像・動画処理に必要な一般的なライブラリが含まれます
  • それ以外のシステムライブラリが必要な場合、アプリは動作しない可能性があります
  • apt-get 等によるパッケージ追加はできません(非 root のため)
  • command で起動した単一プロセスが基本です
  • systemd やデーモン管理は使えません
  • バックグラウンド処理が必要な場合は workers を使ってください
  • CPU とメモリはプランの Compute Class に応じて割り当てられます
  • アプリごとの個別設定ではなく、ワークスペース内の全アプリに共通の性能帯が適用されます

言語ランタイムが対応していても、依存ライブラリやシステム要件によってはデプロイできない場合があります。

言語パッケージマネージャで追加できる依存

Section titled “言語パッケージマネージャで追加できる依存”

以下のパッケージマネージャで管理される純粋な言語パッケージは問題なくインストールできます。

  • Python: pip(requirements.txt
  • Node.js: npm(package.json
  • Go: go mod(go.mod

依存関係は command 内でインストールします。

# Python
command: "pip install --user -r requirements.txt && python app.py"
# Node.js
command: "npm install && npm start"
# Go (Keelson 側で deploy 時に `./app` がビルドされます)
command: "./app"

ネイティブ依存が必要なパッケージ

Section titled “ネイティブ依存が必要なパッケージ”

一部のパッケージは、C ライブラリやシステムレベルの依存を必要とします。

  • -media ランタイムで動作するもの: Pillow、opencv-python、sharp、ffmpeg 関連など、一般的なメディア処理ライブラリ
  • 動作しない可能性があるもの: ランタイムに含まれないシステムライブラリに依存するパッケージ

サポート対象外になる典型パターン

Section titled “サポート対象外になる典型パターン”
パターン理由
apt-get install が必要非 root でパッケージ追加不可
特殊な C ライブラリに依存ランタイムに含まれていない可能性
GPU を前提とした推論ライブラリGPU インスタンス未提供
データベースサーバー(PostgreSQL、MySQL、Redis)外部サービスとして接続は可能だが、Keelson 上での起動は不可
systemd やバックグラウンドデーモン前提プロセスモデルが異なる

デプロイモードは選択するものではなく、commandassets という持ち物から自動的に決まる導出値です。CLI / API の出力は deploy_mode の生ラベルを返すため、対応表で読み替えてください。

呼称deploy_mode 生ラベルcommandassets説明
Web アプリcontainerありなし通常のアプリデプロイ
静的サイトedge-staticなしあり(fallback なし)静的ファイルのみ
SPAedge-spaなしあり(fallback あり)SPA(フォールバック付き)
ハイブリッドhybridありあり(fallback 必須)静的ファイル + バックエンド API

Keelson がアプリのホスト上で予約する URL 名前空間は /__keelson/* の 1 つだけです。それ以外のパスはすべてアプリのものです。/assets/files/static/uploads/api のような一般的なパスをプラットフォームが奪うことはありません。

  • /__keelson/* はプラットフォーム内部用です。プラットフォームが配信するアセット・ファイルダウンロード・内部エンドポイントに使われます。この配下にアプリのルートを定義しないでください。
  • ビルド出力の配信ルート直下に __keelson ディレクトリを出力しないでください。 予約パスを含むビルドはビルド時にエラーコード reserved_path_conflict で拒否されます。ディレクトリ名を変更して再デプロイしてください。
  • それ以外は予約されていません。 /assets/*(Vite の既定出力先)などのフレームワーク既定パスは、設定変更なしでそのまま配信されます。
  • 関連ルール: auth.endpoints のパスは /__keelson で始められません(/api/external/ または /api/webhooks/ で始める必要があります)。また slug に予約語は使えません。

フレームワーク静的パス衝突マトリクス(参考)

Section titled “フレームワーク静的パス衝突マトリクス(参考)”

主要フレームワークが既定で出力する静的パスの一覧です。いずれも /__keelson/* とは衝突しません。参考情報であり、実測 = 本リポジトリで確認済み、それ以外は 要検証(知識ベースの推定。根拠として使わず、必要なら確認すること)です。

フレームワーク既定の静的パス/__keelson と衝突状態
Vite(Vue / Svelte / React / Solid / Preact)/assets/*しない実測
Remix v2 / VitePress/assets/*しない見込み要検証
Angular/assets/*しない見込み要検証
Next.js/_next/static/*しない見込み要検証
Nuxt / SvelteKit / Astro/_nuxt/* · /_app/* · /_astro/*しない見込み要検証
CRA / Django / Flask/static/*しない見込み要検証

アプリの起動に必要な API キー、トークン、接続情報は、コードに直接埋め込まず、環境変数またはシークレットとして設定してください。

  • keelson.yamlenv — バージョン管理に含めてよい値
  • コンソールのシークレット — API キーやトークンなど、コードに含めたくない値

必要な値が未設定の場合、アプリは正常に起動できないことがあります。

詳細は 環境変数とシークレット を参照してください。

変数名説明
TZタイムゾーン(Asia/Tokyo
KEELSON_APP_IDアプリの内部 ID
KEELSON_TENANT_IDテナントの内部 ID

対象制限
HTTP リクエスト一般的なタイムアウトが適用
定期実行ジョブ(cron)1〜3,600 秒(デフォルト 300 秒)
ビルド制限あり(依存関係の量による)

  • アプリから外部 API やサービスへの通信はデフォルトで可能です

症状原因対処
ビルド成功、起動後すぐ落ちる0.0.0.0 で listen していないhost="0.0.0.0" を明示
ポートに接続できないポート番号がハードコード環境変数 PORT から読み取る
モジュールが見つからないcommand に依存インストールが含まれていないpip install / npm installcommand に含める
ネイティブモジュールのビルド失敗システムライブラリ不足-media ランタイムに変更、または依存を見直す
起動コマンドが見つからないエントリポイントのパスが間違いファイル名・パスを確認
ビルドが reserved_path_conflict で失敗ビルド出力の配信ルート直下に __keelson(予約 URL プレフィックス)があるディレクトリ名を変更(予約は /__keelson/* のみ、それ以外はアプリのもの)
  1. ビルドログを確認 — 依存関係のインストールが成功しているか
  2. 実行ログを確認 — 起動時エラーやランタイムエラーがないか
  3. keelson.yaml を確認runtimecommandenv の設定が正しいか

AI エージェントは、Keelson へのデプロイ時に以下の順序で判断してください。

  1. ランタイム確認 — アプリの言語がこの仕様の対応ランタイムに含まれるか確認する
  2. 依存関係確認 — ネイティブ依存やシステムライブラリの要件が制約内か確認する
  3. keelson.yaml 確認 — ファイルの有無と設定内容の妥当性を確認する。なければ作成する
  4. 環境変数確認 — 必要な環境変数やシークレットが不足していないか確認する
  5. デプロイ実行 — CLI または Skill を使ってデプロイを実行する
  6. 完了確認 — ビルド完了だけでなく、起動・ヘルスチェック・URL アクセスまで確認する
  7. 失敗時対応 — ログを確認し、修正可能な範囲で対処する。制約違反がある場合は理由を明示して停止する
  • 非対応ランタイムの場合は、デプロイを試行しない。理由を明示して停止する
  • 必須設定が不足している場合は、必要事項を提示する
  • ビルド成功のみで完了扱いにしない
  • 起動失敗時は必ずログを参照する
  1. Web 上の最新 Keelson Deploy Spec(この文書)
  2. Web 上の最新 CLI バージョン情報
  3. Skill 同梱版の仕様
  4. 一般知識・推測

Web 上の正本と Skill 同梱の情報が矛盾する場合は、Web 上の正本を優先してください。


keelson.yaml

keelson.yaml は、プロジェクトルートに配置するデプロイ設定ファイルです。アプリのランタイム、起動コマンド、環境変数、データベース、定期実行ジョブなどを定義します。

デプロイ時に Keelson はこのファイルを読み取り、その内容に基づいてビルドと実行環境を決定します。

slug: my-app
runtime: python-slim
command: "python app.py"
env:
PORT: "8080"

フィールド必須デフォルト説明
slugstringはいアプリの識別子(URLの一部になります)
typestringnullアプリ種別。"web" のみ指定可。指定時は cronsworkers 不可
runtimestringはい実行環境。対応ランタイムを参照
commandstring | list条件付き起動時に実行するコマンド。crons がない場合は必須
envmap{}環境変数
databaseslist[]SQLite データベースの設定
cronslist条件付き[]定期実行ジョブ。command がない場合は必須
workerslist[]バックグラウンドワーカー
storageobject{}非推奨の disk_id のみを受理する互換ブロック。一般ファイルの永続化は設定しない
assetsobjectnull静的アセット配信の設定

アプリの識別子です。公開URLの一部として使われます(例: my-app.keelson.run)。

slug: my-app

ルール:

  • 使用できる文字: 小文字英数字とハイフン(a-z, 0-9, -
  • 長さ: 1〜63文字
  • --(連続ハイフン)は使用不可
  • 予約語: api, console, www, admin(これが現時点での完全な一覧です)

アプリ種別を指定します。省略可能です。

type: web

指定できる値は "web" のみです。type: web を指定すると、静的アセット配信(assets)が有効になり、command なしでのデプロイが可能になります。

制約:

  • type: web を指定した場合、crons および workers は使用できません

アプリの実行環境を指定します。静的サイトのみのデプロイでも必須です。

ランタイム言語用途
python-slimPython軽量。テキスト処理、API など
python-mediaPythonメディア処理向け(画像・動画ライブラリ含む)
node-slimNode.js軽量
node-mediaNode.jsメディア処理向け
go-slimGo軽量
go-mediaGoメディア処理向け

迷った場合は -slim から始めてください。メディア処理系のライブラリが必要になった場合に -media へ切り替えます。


起動時に実行するコマンドです。依存パッケージのインストールなどの準備処理を含めることもできます。文字列またはリスト形式で指定できます。

# 文字列形式(シェル経由で実行)
command: "python -m pip install -r requirements.txt && python app.py"
# リスト形式(exec 形式で実行)
command:
- python
- app.py

ルール:

  • commandcrons のどちらかは必須です(両方指定も可)
  • type: webassets のみのデプロイでは省略可

環境変数をキーと値のペアで定義します。値はすべて文字列として扱われます。

値は必ず引用符で囲んでください。 引用符の無い値は env_value_not_string で 拒否され、デプロイは開始されません。数値・真偽値も同様に引用符が必要です (NODE_ENV: production / RETRIES: 3 / DEBUG: true はいずれも拒否)。

env:
PORT: "8080"
NODE_ENV: "production"
DEBUG: "false"
LOG_LEVEL: "info"

引用符が必須なのは、keelson.yaml を CLI(YAML 1.2)と API(YAML 1.1)の 2 つの 実装が解析しており、引用符の無いスカラーの型解決が食い違うためです。たとえば K: 0o123 は経路によって "83" にも "0o123" にもなり、どちらもエラーを 出さないまま別の値がデプロイされていました。引用符で囲めばどちらの実装でも 同じ文字列になります。

引用符を付けない key は、英字かアンダースコアで始まり、英数字とアンダースコアだけで 構成される必要があります(NODE_ENVDB_POOL など通常の環境変数名はそのまま書けます)。 加えて、次の語は引用符なしでは使えません:

yes Yes YES no No NO true True TRUE false False FALSE on On ON off Off OFF null Null NULL

これらは YAML 1.1 で真偽値・null として解釈されるため、引用符が無いと 2 つの実装で 環境変数の名前や個数が変わってしまいます

引用符を付ければ任意の key が使えます。

env:
NODE_ENV: "production" # そのまま書ける
"MY-VAR": "x" # ハイフン入りは引用符が必要
"yes": "x" # 予約語は引用符が必要

また、env を YAML の merge key(<<)で組み立てることはできませんenv の重複宣言、および env 内での同じ key の重複も拒否されます。


アプリのデータベースの扱いを選択します。新規アプリでは mode: libsql(自動で用意されるデータベース・設定不要)を推奨します。

db:
mode: libsql # libsql | none。レガシー別名 `turso` は `libsql` に正規化されます
フィールド必須デフォルト説明
modestringnonelibsql / none のいずれか(tursolibsql の別名)
mode意味ティア
libsql自動で用意されるデータベース(推奨)。アプリごとに専用のデータベースを自動プロビジョニングし、テナント / アプリ単位で分離。接続情報(KEELSON_DB_URL / KEELSON_DB_AUTH_TOKEN)が環境変数で注入される。契約・接続設定は不要・無料枠内。scale-to-zero 可標準
noneKeelson は DB を管理しない(既定)。DB 不要、または外部 DB を直接持ち込む場合標準

ルール:

  • db を省略した場合、modenone として扱われます(既存の keelson.yaml は従来どおり動作)
  • 自動で用意されるデータベースを使うには mode: libsql を明示指定してください
  • /data 上のファイル SQLite を永続化する経路は提供しません(ファイル DB は永続化されません)

外部データベースを使う場合(mode: none): 自動で用意されるデータベースは設定不要・無料枠内で使えますが、Postgres・MySQL・外部の libSQL などを使いたい場合は mode: none を指定し、接続情報を secrets として自分で設定します(プラットフォームは外部 DB の接続情報を注入しません)。ファイル SQLite を前提とするフレームワーク(Django 等)は、この外部データベース経路で持ち込んでください。


定期実行ジョブを定義します。Keelson がスケジュールに従ってジョブを起動・実行します。

crons:
- name: cleanup
schedule: "0 3 * * *"
command: "python cleanup.py"
timeout: 60
フィールド必須デフォルト説明
namestringはいジョブ名。小文字英数字とハイフン、1〜63文字
schedulestringはいcron 式(5フィールド形式)
commandstring | listはい実行コマンド
timeoutint300タイムアウト(秒)。1〜3600

ルール:

  • 最大 10 個まで定義可能
  • name の重複不可
  • type: web との併用不可
意味
* * * * *毎分
0 * * * *毎時 0 分
0 3 * * *毎日 3:00
0 0 * * 1毎週月曜 0:00

バックグラウンドワーカーを定義します。ワーカーは**常駐プロセスではなく「定期ドレイン」**です。プラットフォームが every 間隔ごとにワーカーを起こし、command を 1 回実行し、溜まった仕事を処理して exit すると止まります。tick と tick の間はプロセスが存在しません。

ワーカーは Web アプリとは別のコンテナで実行されるため、/data を共有しません。durable な状態はデータベース(db.mode: libsql)またはオブジェクトストレージに置いてください(ワーカーが /data に書いたファイルは破棄されます)。

db:
mode: libsql
workers:
- name: drain
command: "python worker.py"
every: 10m
timeout: 2m
フィールド必須デフォルト説明
namestringはいワーカー名。小文字英数字とハイフン、1〜63文字
commandstring | listはい実行コマンド。溜まった仕事を処理して exit 0 する drain 型で書く
everystring30mtick 間隔。許容値は下記
timeoutstring5m(duty 上限で切り下げ)1 tick の kill 期限。duty 規則で上限が決まる

every(tick 間隔)の許容値:

  • 分値: 5m / 10m / 15m / 20m / 30m / 60m(60 を割り切る値)
  • 時間値: 2h / 3h / 4h / 6h / 8h / 12h / 24h(24 を割り切る値)

timeout と duty 規則: timeout ≤ every × 1/5(duty cycle 20% 以下)。例: every: 30m なら timeout は最大 6m。既定は 5m で、短い every では上限まで自動的に切り下げられます。

ルール:

  • ワーカーの本数はプランによって異なります(下記「プラン制限」参照)
  • トップレベルの command が設定されている場合のみ使用可
  • type: web との併用不可
  • replicas / resources は指定できません(CPU / メモリはアプリ単位で設定され、ワーカーに replica 数の概念はありません)

storage は非推奨の disk_id だけを受理します。値は無視され、永続ストレージや /data の自動同期を有効にしません。

一般ファイルの永続 I/O は keelson.yaml では設定できません。オブジェクトストレージへ直接読み書きするデータファイル SDK を後続タスクで提供予定です。

storage:
disk_id: my-disk
フィールド必須デフォルト説明
disk_idstringnull非推奨・無視される旧ストレージ識別子。小文字英数字とハイフン、1〜32文字

静的アセット配信の設定です。静的サイトや SPA のデプロイ、バックエンド API とのハイブリッド構成に使用します。

assets:
dir: dist
fallback: index.html
api: /api
フィールド必須デフォルト説明
dirstringはいアセットディレクトリ(プロジェクトルートからの相対パス)
fallbackstringnullSPA 用フォールバックファイル(例: index.html
apistringnullバックエンド API のパスプレフィックス(例: /api

api を指定すると、そのパス配下のリクエストはバックエンドアプリへ転送され、それ以外は静的アセットとして配信されます。

ルール:

  • dir.. を含むパスは使用不可
  • api/ で始まる必要があります
  • api/__keelson 配下のパスは使用不可
  • api はトップレベルの command が設定されている場合のみ使用可
  • ハイブリッド構成(assets + command)では fallback が必須

デプロイモードは選択するものではなく、commandassets という持ち物から自動的に決まる導出値です。CLI / API の出力(keelson status --json など)は deploy_mode の生ラベルをそのまま返すため、対応表で読み替えてください。

呼称deploy_mode 生ラベルcommandassetsfallback説明
Web アプリcontainerありなし通常のアプリデプロイ
静的サイトedge-staticなしありなし静的ファイルのみ
SPAedge-spaなしありありSPA(フォールバック付き)
ハイブリッドhybridありあり必須静的ファイル + バックエンド API

設定の組み合わせには以下の制約があります。

ルール説明
command または crons が必須少なくとも一方を指定してください(type: web の静的サイトデプロイを除く)
type: web の排他制約crons および workers とは併用できません
workers には command が必要トップレベルの command がない場合、workers は使用できません
assets.api には command が必要API プレフィックスはバックエンドがある場合のみ指定できます
ハイブリッドには fallback が必要assetscommand を両方指定する場合、fallback は必須です

Web アプリ + SQLite(最も一般的)

Section titled “Web アプリ + SQLite(最も一般的)”
slug: flask-crud
runtime: python-slim
command: "python -m pip install --user -r requirements.txt && python app.py"
db:
mode: libsql
env:
PORT: "8080"
PYTHONUNBUFFERED: "1"
PYTHONUSERBASE: "/deps/.local"
slug: marketing-site
type: web
runtime: node-slim
assets:
dir: dist
fallback: index.html

定期実行ジョブのみ(Web なし)

Section titled “定期実行ジョブのみ(Web なし)”
slug: cron-logger
runtime: python-slim
env:
PYTHONUNBUFFERED: "1"
crons:
- name: heartbeat
schedule: "* * * * *"
command: "python heartbeat.py"
timeout: 30

Web + バックグラウンドワーカー(定期ドレイン)

Section titled “Web + バックグラウンドワーカー(定期ドレイン)”

Web アプリが pending 行をデータベースに書き、ワーカーが every 間隔で溜まった行を処理します。ワーカーは Web と別コンテナで走るため、共有状態は db.mode: libsql に置きます。

slug: task-worker
runtime: python-slim
command: "python app.py"
env:
PYTHONUNBUFFERED: "1"
db:
mode: libsql
workers:
- name: drain
command: "python worker.py"
every: 10m
timeout: 2m

ハイブリッド(静的ファイル + バックエンド API)

Section titled “ハイブリッド(静的ファイル + バックエンド API)”
slug: photo-galleries
runtime: python-slim
command: "python -m pip install --user -r requirements.txt && python app.py"
env:
PORT: "8080"
PYTHONUNBUFFERED: "1"
PYTHONUSERBASE: "/deps/.local"
db:
mode: libsql
assets:
dir: static
fallback: index.html
api: /api
slug: my-go-app
runtime: go-slim
# Keelson が deploy 時に Linux 向け binary を `./app` としてビルドします。
command: "./app"
env:
PORT: "8080"
slug: node-crud
runtime: node-slim
command: "npm install && npm start"
db:
mode: libsql
env:
PORT: "8080"
NODE_ENV: "production"

エラー原因説明
path/data/ で始まっていないdatabases.path/data/ 配下である必要があります
api/ で始まっていないassets.api/ で始まる必要があります
commandcrons もない少なくとも一方を指定してください(type: web の静的デプロイを除く)
workers があるのに command がないworkers はトップレベルの command が必要です
env の値が引用符で囲まれていないtrue/false/数値は YAML に型変換されます。すべて引用符で囲んでください