Installation and Upgrade Guide
Updated: 2026-10-22
This guide covers the supported Recipe Site product installer and release-to-release upgrader on a Linux host using Docker Engine and Docker Compose v2.
Current release and supported upgrade paths
Current stable: v1.0.3 (October 22, 2026). For a new Linux/Docker site, download the full your-kitchen-library-1.0.3.zip archive from https://yourkitchenlibrary.com/download/ and run the installer from that unpacked source. For an existing v1.0.0, v1.0.1 or v1.0.2 installation, use the v1.0.3 easy-upgrade ZIP, or the advanced upgrade-kit/CLI instructions from the new release; do not copy arbitrary files over a live installation or run the fresh installer against its populated database.
v1.0.3 protects the private .recipe-site/updater Docker bind source before migrations or source replacement. Synology users can use Python 3 in place of a missing unzip, supported Container Manager/Docker paths under sudo, and confirmation read from the SSH terminal. The 41 baseline-history migrations are recorded by the fresh baseline; 43 total migrations were tracked in the tested v1.0.3 upgrade environment. Do not mistake baseline count for all post-baseline migrations.
Current Release Notes · Synology NAS Guide · Software Updates · Backup and Restore.
Supported model
The product now treats application files and database migrations as one controlled release operation.
- Fresh installs use
tools/recipe-site-install.shand the clean v1 baseline atsql/baseline/v1.sql. - Existing installations use the new release's
tools/recipe-site-upgrade.sh. - The 41 pre-v1 migrations through account email verification are represented by the v1 baseline and are recorded in
schema_migrations; they are not replayed against an empty database. - Any migration added after the v1 baseline must be explicitly classified in
release/migration-phases.tsvaspre-codeorpost-codebefore the upgrader will run it. .env, runtime media, local release state, and backups are preserved across upgrades.- Before a real upgrade changes schema or application files, the upgrader creates and verifies a database dump and a code snapshot.
- Every successful install/upgrade ends with automated health checks.
The installer/upgrader does not assume a particular home directory or server layout. Portable backup, restore, and disaster-recovery procedures are documented separately in Backup and Restore.
1. Requirements
- Supported Linux server/VM
- Docker Engine
- Docker Compose v2 (
docker compose) bashcurlrsyncfor upgrades- Git when installing from a checkout; a release archive can also be used
- An HTTPS reverse proxy/tunnel for access beyond localhost
Check the main prerequisites:
docker --version
docker compose version
bash --version
curl --version
rsync --version
MariaDB and PHP run inside the product containers; they do not need to be installed on the host.
2. Obtain the release
For a Git checkout:
git clone <repository-url> recipe-site
cd recipe-site
For a packaged release, extract it into its own installation directory and enter that directory.
Do not copy a production .env, database volume, or runtime image tree into a fresh installation unless you are intentionally performing a restore rather than a clean install.
3. First-run configuration
The normal installation is now automatic. When no .env exists,
tools/recipe-site-install.sh creates a private configuration file (mode
0600) from .env.example, generating two independent cryptographically
random 192-bit MariaDB user and root passwords. Matching DB_* application
credentials are set automatically. The secrets are never printed. The installer
does not replace an existing .env file.
The default configuration is:
APP_BASE_URL=http://127.0.0.1:8080
APP_TIMEZONE=UTC
FORCE_HTTPS=0
SECURE_COOKIES=0
WEB_PORT=8080
This is intentionally bound to server localhost only. Docker publishes
the web container as 127.0.0.1:8080:80. For a first Owner login, use the
browser on the server or an authenticated SSH port forward to localhost.
Do not expose it to the LAN or internet over plaintext HTTP, especially
before creating your Owner (an uninitialized site could be claimed).
For installations using a working HTTPS reverse proxy or tunnel from the
start, manually create and edit .env before invoking the installer:
cp .env.example .env
chmod 600 .env
nano .env
You must set non-placeholder database passwords (with matching DB_PASSWORD
and DB_ROOT_PASSWORD), your real APP_BASE_URL=https://...,
FORCE_HTTPS=1 and SECURE_COOKIES=1. Alternatively run
bash tools/recipe-site-configure.sh first to generate safe credentials and
then edit the generated file. The installer fails its preflight if the HTTP
address and cookie/HTTPS settings contradict each other.
Other options you may customize include APP_TIMEZONE (IANA identifier),
WEB_PORT (must agree with the local APP_BASE_URL port),
PHPMYADMIN_PORT, BACKUP_DIR, and independent container names if
hosting multiple copies on one Docker host.
To adjust settings after installation, edit .env and run:
docker compose up -d --force-recreate web
Once the HTTPS reverse proxy is configured, change the site URL to its HTTPS address and enable both security settings. PHP should detect HTTPS from the trusted reverse proxy. Don't make phpMyAdmin/MariaDB publicly accessible.
v1.0.0 historical issue: that immutable archive included a CSP
upgrade-insecure-requests directive even for HTTP-only sites, resulting
in ERR_SSL_PROTOCOL_ERROR and blocked Owner form submissions. This is
corrected in v1.0.1. The security-cookie mismatch is also eliminated for the
new default localhost setup. Do not overwrite the existing v1.0.0 archive or
run its fresh installer over an existing database.
Never commit or share the real .env.
Account-request email
The product supports administrator approval notifications and optional requester email verification. SMTP credentials remain installation secrets in .env; the approval address and verification policy are owner-editable in Admin -> Site Settings.
The relevant .env values are:
ACCOUNT_APPROVAL_EMAIL
REQUIRE_EMAIL_VERIFICATION
MAIL_ENABLED
MAIL_HOST
MAIL_PORT
MAIL_USERNAME
MAIL_PASSWORD
MAIL_ENCRYPTION
MAIL_FROM_ADDRESS
MAIL_FROM_NAME
Keep MAIL_ENABLED=0 and REQUIRE_EMAIL_VERIFICATION=0 until outbound SMTP has been configured and tested. Never place the real mail password in source control or database-backed Site Settings.
4. Fresh-install preflight
A dry run changes nothing:
bash tools/recipe-site-install.sh --dry-run
If .env does not exist, the dry run reports that private settings will be generated during real installation; it does not create them during the dry run.
The fresh installer is fail-closed: after the MariaDB service starts, the selected application database must contain zero tables. If it already contains tables, use the upgrader for an existing Recipe Site or the documented restore process for a recovery.
5. Fresh install
Run:
bash tools/recipe-site-install.sh
For noninteractive automation after you have independently verified the target and .env:
bash tools/recipe-site-install.sh --yes
The installer performs these operations in order:
- generates the private
.envand random database credentials if needed, then validates security settings and product files; - starts the database service and waits for readiness;
- refuses to continue unless the application database is empty;
- loads
sql/baseline/v1.sql; - verifies the baseline migration ledger;
- applies any future post-baseline migrations with explicit release phases;
- creates runtime media directories;
- repairs only the runtime-writable permissions that need it;
- builds/starts the Compose services;
- runs
tools/recipe-site-health.sh; - records local release state under
.recipe-site/.
Successful completion ends with:
INSTALL=PASS
What the v1 baseline contains
The baseline is a clean product database, not a production clone. It contains:
- the current 33-table schema;
- current foreign keys/indexes/column definitions;
- built-in roles;
- permissions and role-permission grants;
- the current category taxonomy;
- generic owner-editable site-setting defaults;
- migration-history rows for the 41 migrations already represented by the baseline.
It intentionally contains no users, recipes, ratings, favorites, cooking history, shopping data, audit records, import logs, production contact endpoint, or production ID counters. tags and recipe_tags remain in the schema for possible future tag support, but the baseline seeds no tags.
6. Create the first Owner
After INSTALL=PASS, open:
/setup-owner.php
Locally, using the default port:
http://127.0.0.1:8080/setup-owner.php
The first-owner page:
- works only while no active Owner exists;
- requires the established 12-character minimum for a user-selected password;
- creates the initial Owner and logs that user in;
- locks itself after an active Owner exists;
- fails closed if it cannot safely determine Owner state.
See First Owner Setup.
7. Health checks
The supported health check is:
bash tools/recipe-site-health.sh
It verifies, among other things:
- database and web Compose services are running;
- database connectivity;
- critical PHP syntax;
- runtime media directories;
- no pending/unclassified release migrations;
mariadb-check --check --quick;- local home/login/setup endpoints;
- MariaDB has no host port binding.
Success ends with:
RECIPE_SITE_HEALTH=PASS
8. Release-to-release upgrade
Do not overwrite the current installation with new release files first. Obtain/extract the new release into a separate directory, then run the upgrader from that new release against the existing installation.
Example layout:
/home/user/recipe-site # existing installation
/home/user/recipe-site-release-new # newly downloaded/extracted release
From the new release tree:
cd /home/user/recipe-site-release-new
bash tools/recipe-site-upgrade.sh \
--install-dir /home/user/recipe-site \
--dry-run
Review the reported release/migration/copy plan. Then run the real upgrade:
bash tools/recipe-site-upgrade.sh \
--install-dir /home/user/recipe-site
For separately controlled automation:
bash tools/recipe-site-upgrade.sh \
--install-dir /home/user/recipe-site \
--yes
A successful upgrade ends with:
UPGRADE=PASS
9. What the upgrader preserves
The release copy deliberately excludes these installation-specific paths:
.env
.git/
.recipe-site/
www/assets/images/
backups/
node_modules/
That preserves local secrets/configuration, Git metadata when present, release logs/state, recipe/avatar/import/site images, in-tree backups if someone uses them, and local dependency state.
The product's default backup location is outside the installation tree (../recipe-site-backups) so release-file replacement cannot remove backups.
10. Upgrade safety and ordering
Before changing schema or release files, the upgrader creates:
- a fresh MariaDB dump named like
pre-upgrade-recipes_*.sql; - a SHA-256 checksum for that dump;
- a pre-upgrade code snapshot named like
pre-upgrade-code_*.tar.gz; - a SHA-256 checksum for that snapshot;
- an upgrade log under
.recipe-site/upgrade-logs/.
The migration runner compares sql/migrations/*.sql with the database schema_migrations ledger.
Every pending migration must appear in:
release/migration-phases.tsv
with one of:
pre-code
post-code
The upgrader refuses an unclassified pending migration rather than guessing the required order.
pre-codemigrations run before release files change.- If any
post-codemigration is pending, the web service is stopped before new application files are installed, those migrations are then applied, and the service is rebuilt/restarted afterward.
Each applied migration must register its own filename in schema_migrations; otherwise the upgrade stops.
This protects against running new application code against an incompatible schema and against silently replaying historical migrations.
11. Failure / recovery
Interrupted-upgrade limitation (v1.0.3): although backups and checksums are verified before mutation and the missing updater bridge is now created early, an interrupted migration or Docker restart still requires inspection of the saved log, migration ledger, file state and snapshots. Do not blindly retry or manually mark a release successful. Broader interruption/restore/retry tests are tracked under issue #561; preserve the database/media and obtain a known-good restore point before another attempt.
If an upgrade stops before UPGRADE=PASS, do not keep retrying blindly.
- Read the upgrade log under
.recipe-site/upgrade-logs/. - Note the printed pre-upgrade DB dump and code snapshot paths.
- Determine whether the failure occurred before or after a migration/file-copy step.
- Use those verified recovery artifacts and the backup/restore procedures before making further destructive changes.
The upgrader intentionally creates recovery material before changing the installation, but full clean-machine disaster-recovery testing is a separate v1 release-readiness step. See Backup and Restore.
12. HTTPS / public access
The Compose web service and phpMyAdmin bind to 127.0.0.1 by default. MariaDB has no host port binding.
Expose the site through HTTPS using an appropriate reverse proxy/tunnel such as Cloudflare Tunnel, Caddy, Nginx, or Apache proxy. Do not expose MariaDB or phpMyAdmin directly to the internet.
For a network-accessible production installation keep:
FORCE_HTTPS=1
SECURE_COOKIES=1
unless the deployment architecture has a documented reason otherwise.
13. Runtime permissions
The portable permission helper is:
bash fix-permissions.sh
It confines writable ownership/mode repair to runtime media directories instead of recursively rewriting source-code ownership. It determines the installation owner dynamically and uses www-data when available.
Do not use world-writable 777 as a normal configuration.
14. Backup / restore and host maintenance
An existing installation may also have its own host-specific scheduled backup and retention system. Those local scripts are separate from the portable product installer and recovery tools.
For backup and recovery procedures see:
The self-hosted development runner cleanup remains separate:
bash tools/cleanup-runner-retention.sh --dry-run
Do not use runner cleanup to delete database/media/site backups.
15. Release maintenance rule
When adding a database migration after the v1 baseline:
- add the SQL file under
sql/migrations/; - make the migration record itself in
schema_migrationsafter successful work; - add the filename and explicit
pre-codeorpost-codephase torelease/migration-phases.tsv; - test it against a representative older release/database;
- verify backup, preservation, ordering, and health-check behavior before shipping the release.
Do not edit sql/baseline/v1.sql for ordinary post-v1 upgrades. It is the v1 fresh-install starting point; evolution from shipped releases belongs in tracked migrations.
16. Documentation
Start with Documentation Index.
working/CHAT_HANDOFF.mdworking/PROJECT_STATUS.mdworking/NEW_THREAD_PROMPT.md
