WP Launcher is configured via a .env file in the project root. The installer generates this automatically, but you can customize it.
| Variable | Description | Default |
|---|---|---|
BASE_DOMAIN | Base domain for site subdomains | localhost |
NODE_ENV | Environment mode | development |
API_KEY | API key for machine-to-machine auth | Auto-generated |
ADMIN_EMAIL | First admin account email | — |
JWT_SECRET | Secret for JWT token signing | Auto-generated |
PUBLIC_URL | Public URL of the dashboard | http://localhost |
SMTP_HOST | SMTP server hostname | — |
SMTP_PORT | SMTP server port | 587 |
SMTP_USER | SMTP username | — |
SMTP_PASS | SMTP password | — |
SMTP_SECURE | Use implicit TLS (port 465 = true, port 587 = false) | false |
SMTP_FROM | From address for system emails | — |
WP_IMAGE | Base WordPress Docker image tag | wp-launcher-wp |
MAX_SITES_PER_USER | Maximum active sites per user | 3 |
MAX_TOTAL_SITES | Maximum total active sites | 50 |
CONTAINER_MEMORY | Memory limit per WordPress container | 256m |
CONTAINER_CPU | CPU limit per WordPress container | 0.5 |
ENABLE_TLS | Enable HTTPS via Traefik | false |
CERT_RESOLVER | Traefik certificate resolver name | letsencrypt |
DEFAULT_PHP | Default PHP version for new sites | 8.3 |
DEFAULT_DB | Default database engine for new sites | sqlite |
SHARED_DB_ROOT_PASSWORD | Root password for the shared MySQL/MariaDB servers. Required since v2.5.0 — Compose refuses to start without it | Auto-generated |
SITE_EXPIRY_HOURS | Auto-expiry duration for demo sites | 72 |
API_PORT | Host port for the API service | 3000 |
WP Launcher uses role-based authentication. There are three ways to create the first admin:
ADMIN_EMAIL in .env — the first user to register with that email is auto-promoted to adminwpl admin:promote [email protected] to promote any existing userThe API_KEY in .env is for machine-to-machine authentication (e.g., CI/CD pipelines). It provides admin-level access to all API endpoints.
Product templates are JSON files in the products/ directory. Here's the full schema:
{
"id": "my-product",
"name": "My Product Demo",
"database": "sqlite",
"plugins": {
"preinstall": [
"woocommerce",
{ "source": "url", "url": "https://example.com/plugin.zip" },
{ "source": "local", "path": "my-plugin.zip" }
],
"remove": ["hello", "akismet"]
},
"themes": {
"install": ["flavor"],
"active": "flavor",
"remove": ["twentytwentyfour", "twentytwentythree"]
},
"demo": {
"expiration": 72,
"maxConcurrentPerUser": 3,
"adminUser": { "username": "demo", "password": "demo123" },
"landingPage": "/shop/"
},
"restrictions": {
"disableFileModifications": true,
"hiddenMenus": ["tools.php", "options-general.php"],
"blockedCapabilities": ["install_plugins", "edit_themes"]
},
"branding": {
"bannerText": "Try My Product",
"description": "A demo of My Product plugin",
"image": "https://example.com/banner.png"
},
"docker": {
"image": "wp-launcher-wp-my-product"
}
}Three methods for including plugins in product templates:
| Source | Syntax | Description |
|---|---|---|
| WordPress.org | "woocommerce" | Free/public plugins by slug — downloaded during image build |
| URL | {"source": "url", "url": "..."} | Premium plugins via direct ZIP download URL |
| Local | {"source": "local", "path": "file.zip"} | Private/custom plugins from product-assets/<product-id>/ |
To display plugin icons in the dashboard, use this URL pattern:
https://ps.w.org/PLUGIN-SLUG/assets/icon-256x256.pngReplace PLUGIN-SLUG with the plugin's WordPress.org slug (e.g., woocommerce, contact-form-7).