Install Folio on Easypanel
You run Easypanel on your own server. A template is two files (the form and the texts, and the services to create), plus a logo and a screenshot. Until the template is published, create the three services by hand.
What you need
- An Easypanel server with 2 GB of RAM or more.
Steps
Step 1: In a project: + Service > Postgres. Name it folio-db. Note the generated password.
Step 2: + Service > Redis. Name it folio-redis. Note its password.
Step 3: + Service > App. Name it folio. Under Source choose Docker image and enter the image below.
Imageghcr.io/evergreen-it-dev/folio:latestStep 4: Under Environment, replace the words in angle brackets. The project name is shown at the top of Easypanel; the database name is the project name.
EnvironmentNODE_ENV=production PORT=4870 PUBLIC_URL=https://wiki.example.com DATABASE_URL=postgresql://postgres:<db password>@<project>_folio-db:5432/<project> REDIS_URL=redis://:<redis password>@<project>_folio-redis:6379 ASSET_BACKEND=local FOLIO_SECRET=<run: openssl rand -hex 32>Step 5: Under Domains add your domain, port 4870.
Step 6: Under Mounts add a Volume named data at /app/data.
Step 7: Deploy. Open the address. The first account is the administrator.
Files
The template's index.ts does the same steps and generates both passwords and the secret. The template is not in Easypanel's catalog yet.
Show index.ts (64 lines) and copy it
import { Output, randomPassword, randomString, Services } from "~templates-utils";
import { Input } from "./meta";
export function generate(input: Input): Output {
const services: Services = [];
const databasePassword = randomPassword();
const redisPassword = randomPassword();
// Encrypts saved Git tokens and personal AI keys. Generated once; never change it.
const folioSecret = randomString(64);
services.push({
type: "app",
data: {
serviceName: input.appServiceName,
env: [
`NODE_ENV=production`,
`PORT=4870`,
`PUBLIC_URL=https://$(PRIMARY_DOMAIN)`,
`DATABASE_URL=postgresql://postgres:${databasePassword}@$(PROJECT_NAME)_${input.appServiceName}-db:5432/$(PROJECT_NAME)`,
`REDIS_URL=redis://:${redisPassword}@$(PROJECT_NAME)_${input.appServiceName}-redis:6379`,
`ASSET_BACKEND=local`,
`FOLIO_SECRET=${folioSecret}`,
`CURSOR_AGENT_WORKSPACE_ROOT=/app/data/assistant/workspaces`,
`CURSOR_AGENT_STATE_DIR=/app/data/assistant/state`,
].join("\n"),
source: {
type: "image",
image: input.appServiceImage,
},
domains: [
{
host: "$(EASYPANEL_DOMAIN)",
port: 4870,
},
],
mounts: [
{
type: "volume",
name: "data",
mountPath: "/app/data",
},
],
},
});
services.push({
type: "postgres",
data: {
serviceName: `${input.appServiceName}-db`,
password: databasePassword,
},
});
services.push({
type: "redis",
data: {
serviceName: `${input.appServiceName}-redis`,
password: redisPassword,
},
});
return { services };
}Settings
Optional variables go in the same Environment field.
| Variable | Default | What it does |
|---|---|---|
FOLIO_SECRET | required | Encrypts saved Git tokens and AI keys. Never change it later. |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET | empty | Turn on "Sign in with Google". Register <your address>/api/auth/google/callback with Google. |
GOOGLE_ALLOWED_DOMAINS | empty | Email domains allowed to sign in with Google. Empty means nobody. |
CURSOR_API_KEY | empty | Shared key for the AI assistant. Without it each person adds their own. |
Update
Change the image tag on the folio service (or keep latest) and Deploy. The database migrates itself on start. Back up first.
Back up
Easypanel can back up its Postgres service to S3 from the service page. The volume data is the other half: copy /app/data from the app's volume (Easypanel's server path is /etc/easypanel/projects/<project>/folio/volumes/data) or from a shell in the app:
tar czf - -C /app/data .Limits and honest notes
- One instance of the app.
- Easypanel's Redis service is password-protected, which the template accounts for.
Platform documentation
Check the installation
From a clone of the repository, run the smoke test against a fresh instance. It needs Node 18 or newer. It creates the first account, a space and a page, and opens a WebSocket connection to the page. Delete the instance, or that space, afterwards.
node deploy/smoke.mjs https://wiki.example.comOther ways to install
Compare all platformsNot ready to install?
Try the public demo: https://demo.foliowiki.online. Pick Sam on the sign-in screen. The login is shared and the data resets every 24 hours, so don't enter personal data or API keys.