Install ASE
ASE is shipped as the Docker image clinuxfr/ase-ops. A production-like deployment uses four services: web, app, scheduler, and database.
Prerequisites
Install Docker and Docker Compose, choose a public URL, and prepare strong secrets for Symfony and MariaDB.
Minimal .env
ASE_IMAGE=clinuxfr/ase-ops
ASE_VERSION=latest
HTTP_PORT=8080
PUBLIC_SCHEME=http
DEFAULT_URI=http://localhost:8080
# Optional. Leave empty to let administrators choose the display timezone in the UI.
APP_TIMEZONE=
APP_SECRET=replace-with-a-long-random-value
MARIADB_DATABASE=ase
MARIADB_USER=ase
MARIADB_PASSWORD=replace-with-a-strong-password
MARIADB_ROOT_PASSWORD=replace-with-a-different-strong-password
MAILER_DSN=
ASE_MAIL_FROM=
ASE_MAIL_FROM_NAME=
ASE_MATTERMOST_WEBHOOK_URL=
ASE_MATTERMOST_USERNAME=
ASE_EXECUTION_LOG_DIR=/app/var/execution-logs Docker Compose file
name: ase
services:
app:
image: ${ASE_IMAGE:?ASE_IMAGE is required}:${ASE_VERSION:-latest}
environment:
APP_ENV: prod
APP_DEBUG: 0
APP_SECRET: ${APP_SECRET:?APP_SECRET is required}
APP_TIMEZONE: ${APP_TIMEZONE:-}
DEFAULT_URI: ${DEFAULT_URI:-http://localhost}
MAILER_DSN: ${MAILER_DSN:-}
DATABASE_HOST: database
DATABASE_PORT: 3306
DATABASE_NAME: ${MARIADB_DATABASE:-ase}
DATABASE_USER: ${MARIADB_USER:-ase}
DATABASE_PASSWORD: ${MARIADB_PASSWORD:?MARIADB_PASSWORD is required}
depends_on:
database:
condition: service_healthy
healthcheck:
test: ["CMD", "php", "bin/console", "app:health:check", "--quiet"]
interval: 10s
timeout: 5s
retries: 5
volumes:
- ./public_assets:/app/public
- ./execution_logs:/app/var/execution-logs
restart: unless-stopped
web:
image: nginx:1.28-alpine
depends_on:
app:
condition: service_healthy
ports:
- "${HTTP_PORT:-8080}:80"
volumes:
- ./public_assets:/app/public:ro
restart: unless-stopped
scheduler:
image: ${ASE_IMAGE:?ASE_IMAGE is required}:${ASE_VERSION:-latest}
environment:
APP_ENV: prod
APP_DEBUG: 0
APP_SECRET: ${APP_SECRET:?APP_SECRET is required}
APP_TIMEZONE: ${APP_TIMEZONE:-}
DEFAULT_URI: ${DEFAULT_URI:-http://localhost}
DATABASE_HOST: database
DATABASE_PORT: 3306
DATABASE_NAME: ${MARIADB_DATABASE:-ase}
DATABASE_USER: ${MARIADB_USER:-ase}
DATABASE_PASSWORD: ${MARIADB_PASSWORD:?MARIADB_PASSWORD is required}
SKIP_MIGRATIONS: 1
depends_on:
app:
condition: service_healthy
command: ["php", "bin/console", "app:scheduler:work", "--no-interaction"]
volumes:
- ./execution_logs:/app/var/execution-logs
restart: unless-stopped
database:
image: mariadb:11.8
environment:
MARIADB_DATABASE: ${MARIADB_DATABASE:-ase}
MARIADB_USER: ${MARIADB_USER:-ase}
MARIADB_PASSWORD: ${MARIADB_PASSWORD:?MARIADB_PASSWORD is required}
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD:?MARIADB_ROOT_PASSWORD is required}
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 10
volumes:
- ./database_data:/var/lib/mysql
restart: unless-stopped First start
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 app Migrations
docker compose exec app php bin/console doctrine:migrations:migrate --no-interaction Scheduler health
The scheduler writes its heartbeat to execution_logs/.scheduler-heartbeat.json. Both the app and scheduler containers must mount the same execution_logs path.
docker compose ps scheduler
docker compose logs --tail=100 scheduler
ls -la execution_logs Reverse proxy and HTTPS
Set DEFAULT_URI to the public URL used in links and notifications. Behind a TLS reverse proxy, set PUBLIC_SCHEME=https and forward host and scheme headers to nginx.
Updating the image
docker compose pull
docker compose up -d
docker compose exec app php bin/console doctrine:migrations:migrate --no-interaction Troubleshooting
Check app health, scheduler logs, database health, and the shared volumes first. Most startup issues come from missing secrets, database readiness, or mismatched volume mounts.