Configuration reference
Framework Cloud reads its settings from environment variables, usually in the
.env file. With Docker, it sits next to compose.yml. After changing it,
restart with docker compose up -d. Without Docker, run
php artisan config:cache.
Server
| Variable | Default | Description |
|---|---|---|
APP_KEY |
none | Encryption key. Required. Generate it once and back it up. |
APP_PREVIOUS_KEYS |
none | Old keys, comma-separated, so saved credentials stay readable after you change APP_KEY. |
APP_URL |
none | The address people use, such as https://framework.example.edu. |
FW_MODE |
self |
self for your own server, where every feature is on. hosted is for Framework Public Cloud (framework.pub). |
FW_ADMIN_EMAIL |
none | The admin account, created on first start. |
FW_ADMIN_NAME |
from the email | The admin's name when the account is created. |
FW_REGISTRATION |
open |
closed stops new sign-ups. Admins can still create accounts with fw:login-link --create. |
FW_DOCUMENTS_DISK |
local |
Storage for published artifacts. Becomes bucket when a bucket is saved on the setup page. |
FW_ARTIFACTS_DISK |
local |
Private storage for new artifacts. Must not have public bucket or web access. Use shared storage for multiple app nodes. |
FW_AGENTS |
true |
false turns off AI agents: the MCP server at /mcp, its OAuth sign-in, and the agent page. Existing connections stop working until it is turned on again. Without it, Server administration can turn agents off. See AI apps. |
FW_TRASH_DAYS |
30 |
Days deleted projects, artifacts, reports, and skills stay in the Trash before they are deleted forever, artifact files included. 0 keeps them until emptied by hand. Docker runs the daily cleanup in the scheduler service. |
FW_CONTENT_URL |
none | A host of its own for published files, such as https://content.example.org, pointing at this app. It serves only signed file links and sets no cookies. Unset, the app serves files. |
TRUSTED_PROXIES |
loopback | Proxies trusted to report the visitor's address and https. cloudflare trusts Cloudflare's edge; * trusts any; or a comma-separated list. |
Sign-in
| Variable | Default | Description |
|---|---|---|
FW_PASSWORDS |
true when FW_MODE=self |
Allows password sign-in alongside email links, passkeys, and GitHub. |
FW_SINGLE_USER |
false |
Signs every local request in as the admin. See Local installation. |
FW_SINGLE_USER_NETWORKS |
127.0.0.1/32,::1/128 |
Addresses that count as this computer in single-user mode, comma-separated. The Docker setup adds its network's gateway when this is unset. |
Docker
These apply only to the Docker setup.
| Variable | Default | Description |
|---|---|---|
FRAMEWORK_CLOUD_VERSION |
latest |
The release to run, such as 1.2.0. |
SERVER_NAME |
none | The domain to get an HTTPS certificate for. :80 serves plain HTTP. |
HTTP_PORT |
80 |
The machine's port for HTTP. |
HTTPS_PORT |
443 |
The machine's port for HTTPS. |
HTTP_BIND |
0.0.0.0 |
The address the ports listen on. 127.0.0.1 makes the server reachable only from this machine. |
TRUSTED_PROXIES |
loopback only | Reverse proxies whose forwarded host and scheme the app trusts: *, or a comma-separated list of addresses and CIDR ranges. |
DB_PASSWORD |
none | The database password. Required. |
FW_PREPARE_DATABASE |
true |
Runs migrations and seeding on start. |
Database
DB_CONNECTION, DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, and
DB_PASSWORD. Framework Cloud is built for PostgreSQL. The Docker setup fills
in the connection details for its own database container.
Server credentials
Each of these can be set here or on the Server setup page. A variable that is set wins. See Server setup.
| Credential | Variables |
|---|---|
| GitHub App | GITHUB_APP_ID, GITHUB_APP_SLUG, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, GITHUB_WEBHOOK_SECRET, GITHUB_APP_PRIVATE_KEY |
| Notebook storage | FW_BUCKET_NAME, FW_BUCKET_ENDPOINT, FW_BUCKET_REGION, FW_BUCKET_KEY, FW_BUCKET_SECRET, FW_DOCUMENTS_BASE_URL |
MAIL_MAILER, MAIL_FROM_ADDRESS, MAIL_FROM_NAME, MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION |
GitHub scaffolding
The scaffold workflow installs a pinned version of the tool that builds the project, so every repository scaffolded from the same server gets the same result.
| Variable | Default | Description |
|---|---|---|
GITHUB_FRAMEWORK_SHA |
a tested commit | The framework R package commit that builds R projects. A full 40-character SHA. Empty turns GitHub scaffolding off. |
GITHUB_FRAMEWORK_PY_SHA |
a tested commit | The framework-py commit that builds Python projects. A full 40-character SHA. Empty turns off Python projects on GitHub. |
GITHUB_FW_VERSION |
a tested release | The fw release that builds Stata projects, such as 0.3.0. Empty turns off Stata projects on GitHub. They can still be set up on a computer. |
GITHUB_FW_SHA256 |
release checksums file | Optional SHA-256 checksum of the fw Linux download. Empty makes the workflow verify the download against the release's checksums file. |
Private storage
FW_LOCAL_STORAGE_ROOT sets the private local filesystem directory. The default
is storage/app/private. Atomic deployments need a persistent directory outside
individual releases. Copy existing private files into that directory before
changing the setting. Back it up with the database. Keep it outside the web root.
Downloads
People can download a new project as a zip. The scaffolder container builds it with the same tools that build projects on GitHub and on people's own computers. The Docker install runs it for you.
| Variable | Default | Description |
|---|---|---|
SCAFFOLDER_URL |
http://scaffolder:8000 with Docker, otherwise empty |
Scaffolder address. Empty disables downloads. |
SCAFFOLDER_TOKEN |
empty | A shared secret the app sends to the scaffolder. Set the same value for both when the scaffolder is reachable from other machines. |
SCAFFOLDER_TIMEOUT |
200 |
Seconds the app waits for a build. |
Documentation sites
The server can also serve the documentation sites for the R package, the
Python package, and the fw command line tool, each on its own host name.
Requests to any other host name get Framework Cloud as usual. A site has
content once it is imported with php artisan fw:docs-import, which reads
docs-site.tar.gz from a file, a folder, or a GitHub release
(--release). Until then, the R site shows the guides and reference that
come with Framework Cloud, and the other two show a page saying the
documentation is not published yet.
| Variable | Default | Description |
|---|---|---|
FW_DOCS_HOST_R |
r.framework.test |
The host name of the R package documentation, such as r.framework.pub. |
FW_DOCS_HOST |
none | The older name for FW_DOCS_HOST_R. It is used when FW_DOCS_HOST_R is not set. |
FW_DOCS_HOST_PY |
py.framework.test |
The host name of the Python package documentation. |
FW_DOCS_HOST_CLI |
cli.framework.test |
The host name of the fw documentation. |
FW_DOCS_REPO_R, FW_DOCS_REPO_PY, FW_DOCS_REPO_CLI |
frameworktools/framework, frameworktools/framework-py, frameworktools/framework-cli |
The GitHub repository whose releases fw:docs-import --release reads. |
FW_DOCS_PRERELEASE_R, FW_DOCS_PRERELEASE_PY, FW_DOCS_PRERELEASE_CLI |
fallback |
Release selection for --release. fallback takes the newest release with docs-site.tar.gz, and a pre-release only when no other release has the file. always takes the newest release of either kind. never skips pre-releases. |
FW_DOCS_PATH |
storage/app/docs |
Imported documentation directory. |
Each host name needs a DNS record that points at the server and a certificate that covers it.
Package server selection
The R and Python packages find the server in this order:
- The
urlargument, as incloud_login("<token>", url = "https://framework.example.edu"). - For commands that work on a project, such as
publish(): theFW_CLOUD_URLline in the project's.envfile. Setting up a project writes it, so a project always goes back to the server that created it. - The
FW_CLOUD_URLenvironment variable. - For your own commands, such as
cloud_status()andnew(): the server you last connected withcloud_login(). https://framework.pub.
Each server has its own token. cloud_logout(url = ...) removes one.
