Deployment
Deploy your Symfony application to production
Basic Deployment
frankendeploy deploy production
This command performs a complete deployment:
- Builds Docker image locally
- Transfers image to server
- Stops old container
- Starts new container
- Runs health checks
- Updates Caddy configuration
- Cleans up old releases
Deployment Options
Custom Tag
frankendeploy deploy production --tag v1.2.3
By default, tags are timestamps like 20240115-143052.
Cross-Architecture Detection
FrankenDeploy automatically detects architecture mismatches between your local machine and the server. When deploying from Apple Silicon (ARM) to an x86_64 VPS, you’ll see:
⚠️ Architecture mismatch detected:
Local: arm64 (Apple Silicon)
Server: x86_64
Local builds will not run on this server.
In interactive mode, FrankenDeploy prompts you to enable remote build and saves your preference for future deployments.
In CI/CD mode (--yes), you must explicitly use --remote-build or pre-configure the server:
# Configure server for remote builds
frankendeploy server set production remote_build true
# Or use the flag
frankendeploy deploy production --remote-build --yes
Remote Build (Recommended for Apple Silicon)
Build the Docker image directly on the server instead of locally:
frankendeploy deploy production --remote-build
This is recommended when:
- Your local machine has a different architecture (Apple Silicon → x86 VPS)
- Local builds are slow due to emulation
- You want faster transfers (source code vs Docker image)
How it works:
- Transfers source code via
rsync(fast, excludes node_modules/vendor) - Builds Docker image on the VPS
- Deploys normally
Force Local Build
If remote build is configured but you want to build locally anyway:
frankendeploy deploy production --no-remote-build
Skip Build
If you’ve already built the image:
frankendeploy deploy production --no-build
Force Deploy
Skip health check failures:
frankendeploy deploy production --force
Health Checks
FrankenDeploy verifies your application is healthy before switching traffic.
Configure in frankendeploy.yaml:
deploy:
healthcheck_path: /health
Create a health endpoint in your Symfony app:
// src/Controller/HealthController.php
#[Route('/health')]
public function health(): Response
{
return new Response('OK');
}
If the health check fails, FrankenDeploy automatically rolls back.
Deployment Hooks
Run commands before and after deployment:
deploy:
hooks:
pre_deploy:
- php bin/console doctrine:migrations:migrate --no-interaction
- php bin/console messenger:stop-workers
post_deploy:
- php bin/console cache:warmup
Pre-deploy hooks run in the new container before traffic is switched. Post-deploy hooks run after successful deployment.
Database Migration Warning
FrankenDeploy automatically detects when your project has Doctrine entities but no migration files. This can happen when you forget to generate migrations after creating entities.
When this situation is detected (entities in src/Entity/ but no files in migrations/), FrankenDeploy displays a warning:
⚠️ Warning: No database migrations found but entities exist!
Entities found: 5 files in src/Entity/
Migrations: 0 files in migrations/
This may cause 'no such table' errors at runtime.
To fix this, run locally:
php bin/console make:migration
php bin/console doctrine:migrations:migrate
git add migrations/
git commit -m "Add database migrations"
Then redeploy your application.
This warning only appears once per application. Once you add migrations and redeploy, the warning is automatically cleared.
Note: This check only runs when you have a migration hook configured in your pre_deploy hooks.
Release Management
FrankenDeploy keeps multiple releases for instant rollback:
deploy:
keep_releases: 5
Releases are stored in /opt/frankendeploy/apps/your-app/releases/.
View releases:
frankendeploy app status production
Environment Variables
Set production environment variables in frankendeploy.yaml:
env:
prod:
APP_ENV: prod
APP_DEBUG: "0"
DATABASE_URL: "${DATABASE_URL}"
For secrets, set them directly on the server or use a secrets manager.
Shared Files and Directories
Files and directories that persist between releases:
deploy:
shared_files:
- .env.local
shared_dirs:
- var/log
- var/sessions
- public/uploads
Zero-Downtime Deployment
FrankenDeploy ensures zero downtime:
- New container starts alongside old one
- Health checks verify new container
- Caddy switches traffic to new container
- Old container is stopped
If anything fails, traffic stays on the old container.
Monitoring Deployments
View Logs During Deploy
Use verbose mode:
frankendeploy deploy production --verbose
Check Deployment Status
frankendeploy app status production
View Application Logs
frankendeploy logs production
frankendeploy logs production -f # Follow mode
CI/CD Integration
FrankenDeploy provides environment variables and flags for seamless CI/CD integration.
Environment Variables
| Variable | Description |
|---|---|
FRANKENDEPLOY_SERVER | Server name to use (alternative to argument) |
FRANKENDEPLOY_SSH_KEY | SSH private key content (base64 or raw) |
FRANKENDEPLOY_KNOWN_HOSTS | Known hosts file content |
FRANKENDEPLOY_SKIP_HOST_KEY_CHECK | Skip host key verification (not recommended) |
Non-Interactive Mode
Use --yes or -y to skip all confirmation prompts:
frankendeploy deploy production --yes
frankendeploy app remove production my-app --force --yes
GitHub Actions Example
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install FrankenDeploy
run: |
curl -fsSL https://raw.githubusercontent.com/yoanbernabeu/frankendeploy/main/scripts/install.sh | sh
- name: Deploy
env:
FRANKENDEPLOY_SERVER: production
FRANKENDEPLOY_SSH_KEY: ${{ secrets.SSH_KEY }}
FRANKENDEPLOY_KNOWN_HOSTS: ${{ secrets.KNOWN_HOSTS }}
run: frankendeploy deploy --yes
GitLab CI Example
deploy:
stage: deploy
image: ubuntu:22.04
script:
- curl -fsSL https://raw.githubusercontent.com/yoanbernabeu/frankendeploy/main/scripts/install.sh | sh
- frankendeploy deploy --yes
variables:
FRANKENDEPLOY_SERVER: production
FRANKENDEPLOY_SSH_KEY: $SSH_PRIVATE_KEY
FRANKENDEPLOY_KNOWN_HOSTS: $KNOWN_HOSTS
only:
- main