Deploying a Kirby CMS Project with DeployHQ
Kirby is a file-based CMS built on PHP — there is no database in a standard setup. Content lives as plain text files inside a content/ directory, media thumbnails are generated on demand, and the admin panel (Kirby Panel) stores user accounts as YAML files. This makes deployment different from database-driven CMS platforms: you need to think carefully about which directories belong in Git and which should persist between releases.
DeployHQ handles this cleanly — automate Composer installs, keep persistent directories intact across releases with zero-downtime deployments, and clear Kirby's cache automatically after every deploy.
This guide assumes you have a server running Apache or Nginx with PHP 8.1+ and Composer installed.
Kirby's File-Based Architecture
Unlike WordPress or Craft CMS, Kirby stores everything in the filesystem:
content/— Pages, articles, and structured data as text files (Markdown + YAML frontmatter)media/— Auto-generated thumbnails and processed imagessite/accounts/— Panel user accounts (hashed passwords, roles)site/cache/— Template cache, pages cache, plugin cachessite/sessions/— Active user sessionssite/config/— Environment-specific configuration files
Every page in Kirby is a folder inside content/, and every field is a line in a text file. When editors make changes through the Panel, those changes write directly to content/ — meaning this directory is modified at runtime, not just at deploy time.
Handling the Content Directory
The biggest decision in a Kirby deployment is whether content/ belongs in your Git repository.
Content in Git (recommended for developer-managed sites):
- Full version history for all content changes
- Content is part of the deployment pipeline
- Works well when developers write content locally and push
- Downside: Panel edits on the server create drift between Git and production
Content outside Git (recommended when editors use the Panel):
- Add
content/to.gitignore - The directory persists on the server across deployments
- Panel edits are never overwritten by a deploy
- Downside: no version control on content unless you set up a separate backup
For most teams using Kirby's Panel in production, keeping content/ out of Git and treating it as a shared persistent directory in DeployHQ is the right approach.
Setting Up DeployHQ
Create a Project
After signing up and logging in, create a project via Projects > New Project. Follow the wizard to connect your Git repository. If you run into connection issues, check DeployHQ's support page.
Create a Deployment User
For security, create a dedicated user on your server:
sudo adduser deployhq
sudo usermod -a -G www-data deployhq
Configure the Server
Go to Servers > New Server and configure an SSH connection:
- Enter a name for the server and select SSH as the protocol
- Set the Hostname to your server's IP address
- Set Username to
deployhq - Check Use SSH key rather than password for authentication?
Then on your server, set up the SSH key:
su - deployhq
mkdir ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
Paste DeployHQ's public key, save with Ctrl + X, y, Enter, then set permissions:
chmod 600 ~/.ssh/authorized_keys
Set the Deployment Path to your project root, e.g. /var/www/kirby-site.
Enable Perform zero-downtime deployments on this server. This creates a current/ symlink that points to the latest release, so your web server root should be set to /var/www/kirby-site/current.
Set Environment to production and enable automatic deployment.
Zero-Downtime Shared Paths
With zero-downtime deployments enabled, each deploy creates a new release directory. Directories that need to persist between releases must be configured as shared paths.
Add these as shared directories:
content— Preserves all page content and Panel editsmedia— Keeps generated thumbnails so they do not need to be regeneratedsite/accounts— Preserves Panel user accounts across releasessite/sessions— Prevents users from being logged out after a deploy
DeployHQ will symlink these directories from a shared location into each new release automatically.
Config Files
Kirby supports environment-specific configuration. If you use a .env file or a site/config/config.production.php, upload it via Config Files > New Config File so it is injected into every release without being stored in Git.
A typical site/config/config.production.php might look like:
<?php
return [
'debug' => false,
'cache' => [
'pages' => [
'active' => true
]
],
'thumbs' => [
'quality' => 80
]
];
Build Pipeline
If your Kirby project uses Composer for plugins or a frontend build step (e.g. Vite, Webpack, or Laravel Mix for CSS/JS), configure these in the build pipeline.
Add a deploy.build.yaml to your repository root:
build:
- composer install --no-dev --optimize-autoloader --no-interaction
- npm ci && npm run build
The --no-dev flag skips development dependencies, and --optimize-autoloader generates an optimized class map for production. The npm step is only needed if you have a frontend build — remove it if your project does not use one.
Kirby Cache Management
Kirby uses several cache layers that need to be cleared after deployment to ensure visitors see the latest content and templates.
Template cache — Compiled PHP templates are cached automatically. After deploying template changes, stale cache files will serve the old version until cleared.
Pages cache — When enabled in config.php, Kirby caches full page HTML output. This dramatically speeds up response times but means content changes (including those pushed via deploy) will not be visible until the cache is cleared.
Plugin caches — Some plugins maintain their own cache buckets.
Post-Deploy Cache Clearing
Configure a post-deployment SSH command via SSH Commands > New SSH Command:
cd %path% && rm -rf site/cache/*
This removes all cache directories in one step. Kirby regenerates caches automatically on the next request.
If you are using Kirby's CLI (available via Composer), you can use the built-in command instead:
cd %path% && php vendor/bin/kirby clear:cache
Recommended command order:
- Composer install (if not handled in build pipeline)
- Clear cache
Media and Thumbnails
Kirby generates image thumbnails on first request and stores them in media/. Without shared paths, every deployment would regenerate all thumbnails — causing slow first-load times for image-heavy pages.
By configuring media/ as a shared directory (covered above), thumbnails persist across releases. New images will have thumbnails generated automatically when first requested.
Kirby License
Kirby requires a license for production use. Register at getkirby.com and add the license key to site/config/config.php or your .env file. Kirby runs without a license locally but displays a warning banner in the Panel on production domains without a valid key.
Multi-Environment Setup
Kirby's configuration system supports multiple environments natively through domain-specific config files:
site/config/config.php— Base configuration (all environments)site/config/config.staging.example.com.php— Staging overridessite/config/config.production.example.com.php— Production overrides
Kirby loads the base config first, then merges in the file matching the current domain. In DeployHQ, set different servers for staging and production branches, each with their own config files.
Deploying
Once everything is configured, click Deploy Project in the header. Select your server and the revision range, then click Deploy. DeployHQ will:
- Pull the latest code from your repository
- Run the build pipeline (Composer, npm)
- Create a new release directory
- Symlink shared paths (content, media, accounts, sessions)
- Inject config files
- Run post-deploy SSH commands (cache clearing)
- Switch the
currentsymlink to the new release
Your Kirby site is now live with zero downtime.
For guides on deploying other frameworks, visit the DeployHQ guides page.
Need help? Reach out to us at support@deployhq.com or on Twitter/X.