Configuration
This chapter explains the Self-hosted Edition's settings: where they go, what each one does, the database, and backing up the whole system. For installing, see the "Installation" chapter.
config.toml or environment variables
Every setting can be written in config.toml (next to server, or mounted into the container) or set as an environment variable. Both can be used together: an environment variable always wins, and config.toml only fills in what isn't already set. Pick whichever suits your setup.
Only the keys below are recognized. A typo or an unknown table stops the app at startup with the offending key named; nothing is silently ignored.
Settings
| Key | Environment variable | Default | What it does |
|---|---|---|---|
database.mode | DATABASE_MODE | — | "embedded" runs the app's own PostgreSQL 16 (Embedded Database Mode). Can't be combined with database.url. |
database.embedded_data_dir | DATABASE_EMBEDDED_DATA_DIR | data | Where the embedded database keeps its files, relative to the directory server runs from. |
database.url | DATABASE_URL | — | Connection string of an external PostgreSQL 16+ database. Can't be combined with database.mode. |
database.max_connections | DATABASE_MAX_CONNECTIONS | 5 | Upper limit of database connections. |
server.ip | IP | 127.0.0.1 | Address to listen on. Use 0.0.0.0 to accept connections from other machines; the Dockerfile included in the tarball already does. |
server.port | PORT | 8080 | Port to listen on. |
server.public_url | PUBLIC_URL | http://127.0.0.1:8899 | The address people use to reach the app, including the port. Used in links and emails. |
server.secure_cookies | SECURE_COOKIES | false | Only send cookies over HTTPS. Turn it on when a reverse proxy in front serves HTTPS. |
server.update_check_enabled | UPDATE_CHECK_ENABLED | true | Check once a day for a newer version and show a notice at the top of the page when there is one. See "Checking for new versions" below. |
server.default_language | DEFAULT_LANGUAGE | zh-TW | zh-TW or en. The Display Language used when the browser sends no supported language, and for emails to a User who has no setting. |
mail.smtp_url | SMTP_URL | — | SMTP server for sign-up confirmations, password resets and invitations. Unset means Mail-less Mode. Start with smtps:// for TLS. |
mail.from | MAIL_FROM | KakePhooa <no-reply@localhost> | Sender of those emails, for example KakePhooa <[email protected]>. |
mail.smtp_username | SMTP_USERNAME | — | SMTP user name, if the server requires one. |
mail.smtp_password | SMTP_PASSWORD | — | SMTP password, if the server requires one. |
auth.signup_policy | SIGNUP_POLICY | closed | closed accepts no new sign-ups; open lets anyone sign up. The very first User is always accepted. |
sso.google.enabled | GOOGLE_LOGIN_ENABLED | true | Offer "Log in with Google" when the two keys below are set. |
sso.google.client_id | GOOGLE_CLIENT_ID | — | Google OAuth client ID. |
sso.google.client_secret | GOOGLE_CLIENT_SECRET | — | Google OAuth client secret. |
A Self-hosted Edition deployment supports one User whatever signup_policy says (see "Your User" in the "Installation" chapter), so closed is the usual choice.
Checking for new versions
Once a day the app fetches the latest version information from https://kakephooa.com/releases/self-hosted/latest.json. When a newer version is out, a notice at the top of the page after you log in lists what's new and links to the releases page. After you choose "Don't show this version again", this browser stops showing that version.
The request carries none of your data; it only reads a public file. If it can't connect (for example, the machine has no outbound internet access), nothing is shown and everything else works as usual. To turn the check off, set server.update_check_enabled to false.
Mail-less Mode
Without mail.smtp_url, the app runs in Mail-less Mode: sign-up doesn't send a confirmation email and logs you in straight away, and "Forgot password" can't send a link; use server set-password instead (see the "Installation" chapter).
Using an external database
To use a PostgreSQL 16+ database you already run, edit the [database] table in config.toml: comment out mode = "embedded" and set url to your connection string. mode and url are mutually exclusive: the app refuses to start if both are set, and also if neither is set, rather than silently picking one. For a complete example that runs PostgreSQL in its own container with Docker Compose, see "Docker Compose examples" in the "Installation" chapter.
The embedded database's data directory
In Embedded Database Mode, the database lives under database.embedded_data_dir (data by default; /app/data in the container, which is the data volume in docker-compose.yml). The directory holds the PostgreSQL files (in pgdata/) and a randomly generated database password (a file only its owner can read), created on first start and reused afterwards.
The data directory must be on a local filesystem that supports Linux permissions, because PostgreSQL requires that only its owner can access it. Windows drives (such as /mnt/c under WSL) and network shares (SMB, NFS) can't do that; the app checks at startup and refuses, so set database.embedded_data_dir to a path on a local Linux filesystem. The Windows build, running on a local Windows drive, isn't affected.
PostgreSQL is fixed at major version 16. If the data directory was created by a different major version, the app stops with an error instead of reinitializing it, because reinitializing would throw away the data. Restore a compatible backup, or point database.url at wherever that data actually lives.
Backing up the whole database
A whole-database backup and an in-app Backup are different things:
- A whole-database backup returns everything to a point in time. It's what you need when an upgrade goes wrong or you have to rebuild the machine. In Embedded Database Mode, back up the data directory; for Docker/Podman, for example
docker run --rm -v kakephooa_data:/data -v $(pwd):/backup alpine tar czf /backup/data-backup.tar.gz -C /data .(kakephooa_datais the volume of the includeddocker-compose.yml; adjust it if you changed the compose project). With an external database, usepg_dumpandpg_restoreas usual. - An in-app Backup (Household settings → "Backup") holds one Household's data. Restoring it always creates a new Household (see the "Backups" chapter). It's good for moving to another server or keeping a portable copy, but it isn't a way back from a failed upgrade.
Always take a whole-database backup before upgrading, and keep a portable copy with in-app Backups regularly as well. How often, how many copies and where to keep them is up to you.