Deploy a hosted board
A hosted board is two pieces: the kanban, static on GitHub Pages, and
folio-board-server on Render, which signs people in with GitHub and commits
their edits to the board’s branch. One GitHub App does both jobs: people sign
in with it, and the server writes the repository as it. Nothing here costs
money for an ephemeral GitHub-only service. Durable authorization and SQLite
require a paid persistent disk; see Render and Docker.
GitHub refresh runs automatically when supported by the App.
GitHub Pages (the kanban) ── Sign in with GitHub ──▶ Render: /auth/login ──▶ GitHub
▲ │
└──────── #board-code=<one-time code> ◀────────────┘ /auth/callback
kanban ── Authorization: Bearer <session> ──▶ Render: /v1/… ── commit, push ──▶ board branchWho gets in
Anyone can sign in and connect their repositories. A selected repository must be authorized for both the person and the App. Push access enables editing; read access opens the board without edits. Each commit carries the signed-in person as its author and the server as its committer. A session lasts 8 hours.
Set it up once
Create the GitHub App
GitHub → Settings → Developer settings → GitHub Apps → New GitHub App.
| Field | Value |
|---|---|
| GitHub App name | Any free name, e.g. folio-board |
| Homepage URL | The site, e.g. https://owner.github.io/repo/ |
| Redirect URI | https://<service>.onrender.com/auth/callback |
| Expire user authorization tokens | On |
| Request user authorization during installation | Off |
| Webhook → Active | Off |
| Repository permissions → Contents | Read and write |
| Where can it be installed | Any account |
Metadata: Read-only comes with Contents. Leave every other permission at No access. After creating it, note the Client ID, generate a client secret. Account mode uses each person’s user access token and does not need a private key. An existing App must also allow installation by Any account.
Connect your repositories
The App’s settings → Install App → your account → Only select repositories → the repositories you want to open. Each new user does this for their own account. The screen must list read and write access to code; if it does not, the permission was not saved.
Create the service on Render
Render → New → Blueprint → connect GitHub and this repository. Render
reads render.yaml, builds the Dockerfile and proposes the folio-board
service on the free plan. Folio Docs comes from its public repository, so the
build needs no credentials.
| Setting | Value |
|---|---|
FOLIO_BOARD_MULTI_REPO | true: each person chooses their own repository |
FOLIO_BOARD_GITHUB_APP_SLUG | The App URL slug, folio-board for the deployed App |
FOLIO_BOARD_ORIGIN | The site’s origin, e.g. https://owner.github.io |
FOLIO_BOARD_PUBLIC_URL | The service’s URL, https://<service>.onrender.com |
FOLIO_BOARD_GITHUB_CLIENT_ID | The App’s client id |
FOLIO_BOARD_GITHUB_CLIENT_SECRET | The App’s client secret |
FOLIO_BOARD_SESSION_KEY | Generated by Render; changing it signs everyone out |
If Render names the service differently, set FOLIO_BOARD_PUBLIC_URL and
the App’s Redirect URI to the URL it gives. Account mode is the default on existing services too; set
FOLIO_BOARD_MULTI_REPO=false only for a dedicated single-repository server.
For a dedicated single-repository server, set FOLIO_BOARD_MULTI_REPO=false, set
FOLIO_BOARD_REPO, FOLIO_BOARD_REF and FOLIO_BOARD_PATH, and supply the
App key or FOLIO_BOARD_GITHUB_TOKEN.
Point the kanban at the server
In the site’s docs.yaml, then rebuild and publish the site:
kanban:
api:
url: https://<service>.onrender.comThe published board now offers Sign in with GitHub.
Check it
https://<service>.onrender.com/auth/login?return_to=<a page of the site>
answers with a redirect to GitHub, and /v1/board without a session answers
401. Sign in with a second GitHub account that cannot access this project’s
repository: it must still reach the repository selector. Connect one of that
account’s repositories, select its board branch and directory, and open it.
A save must reach only the selected repository, under that account’s name.
Verify that the second account cannot open the first account’s private repo.
The free plan sleeps
After a while without requests Render stops the service, and the next request waits while it starts. Free services have ephemeral storage; their authorization database disappears on replacement. Use a persistent disk to preserve SQLite boards, API tokens and encrypted credentials across deployments. Expired browser sessions reconnect through GitHub.
When it fails, the log says why
Render → the service → Logs. The server stops at start with one line that names what to fix, and it logs every sign-in GitHub refuses.
| The log says | Fix |
|---|---|
… is not set; a hosted server reads it from the environment | Set the variable it names in Render |
neither FOLIO_BOARD_GITHUB_APP_KEY, FOLIO_BOARD_GITHUB_APP_KEY_FILE nor … | Add the secret file github-app.pem |
the GitHub App private key is not an RSA PEM | Paste the whole .pem, both ----- lines included |
GitHub refused the App's JWT (401) | The client id and the private key are not the same App’s |
the GitHub App is not installed on owner/name (404) | Install it on that repository, or add it under Repository access |
the GitHub App cannot write owner/name | Contents: Read and write, then accept the request on the installation |
sign-in: GitHub refused it: … | The Redirect URI differs from FOLIO_BOARD_PUBLIC_URL/auth/callback, or the client secret is wrong |
| Repository list is empty | Connect the App to repositories accessible to this GitHub account |
| A second account cannot authorize or install the App | Change the App installation setting to Any account |
| Selector never appears after deploy | Remove FOLIO_BOARD_MULTI_REPO=false in Render, redeploy, and sign in again |
In the browser, a kanban that stays read-only gives its reason in the
status mark’s tooltip, and a page that never offers the sign-in has no
kanban.api in its build.
Persistent container deployments
The current Docker entrypoint runs folio-board-server container, serializing
its configuration from environment values. It includes the remote CLI and MCP.
The committed Render Blueprint adds a paid persistent disk for SQLite, token
hashes and encrypted credentials. Review Render and Docker
before applying it to an existing service.