Infrastructure as Code
Infrastructure as code
Define and manage your entire application infrastructure using YAML configuration files. This allows you to version control your infrastructure, automate deployments, and ensure consistency across environments.
How it works
Infrastructure as code lets you describe your application, services, domains, and secrets in a single YAML file. When you apply this configuration, the platform automatically creates or updates all resources to match your desired state.
Configuration structure
Your infrastructure configuration follows this structure:
apiVersion: v1
kind: Infrastructure
metadata:
name: your-app-name
team: your-team-name-or-id
spec:
application: {...}
domains: [...]
secrets: [...]
volumes: [...]
services: [...]
container_services: [...]
Complete example
Here's a comprehensive example showing all available configuration options:
apiVersion: v1
kind: Infrastructure
metadata:
name: production-app
team: 1 # Your team ID or name
spec:
application:
name: production-app
type: laravel # laravel, nodejs, or wordpress
version: "11.x"
repository:
url: https://github.com/yourorg/yourrepo
owner: yourorg
name: yourrepo
branch: main
runtime:
php_version: "8.4"
nodejs_version: "22"
commands:
build:
- composer install --no-dev --optimize-autoloader
- npm ci
- npm run build
init:
- php artisan migrate --force
- php artisan config:cache
- php artisan route:cache
start: php artisan serve --host=0.0.0.0 --port=8000
settings:
health_check_path: /health
scheduler_enabled: true
replicas: 3
memory: 1024Mi
php:
extensions:
- redis
- imagick
- gd
- zip
settings:
- memory_limit=512M
- max_execution_time=120
- upload_max_filesize=100M
- post_max_size=100M
domains:
- domain: app.example.com
- domain: www.example.com
- domain: api.example.com
secrets:
- key: APP_KEY
value: base64:your_generated_key_here
- key: DB_PASSWORD
value: your_secure_password
- key: STRIPE_KEY
value: sk_live_your_stripe_key
- key: AWS_ACCESS_KEY_ID
value: your_aws_key
- key: AWS_SECRET_ACCESS_KEY
value: your_aws_secret
volumes:
- name: storage
mount_path: /var/www/html/storage
volume_size: 20 # Size in GB
- name: uploads
mount_path: /var/www/html/public/uploads
volume_size: 10
services:
# Database services
- name: database
type: mysql
version: "8.0"
memory: 2Gi
volume_size: 50 # Size in GB
settings:
database: production
- name: postgres
type: postgresql
version: "15"
memory: 2Gi
volume_size: 50
settings:
database: app_production
extensions:
- postgis
- pg_trgm
- uuid-ossp
# Cache services
- name: cache
type: redis
version: "7.2"
memory: 512Mi
volume_size: 1
- name: sessions
type: valkey
version: "7.2"
memory: 256Mi
volume_size: 1
# Queue services
- name: queue
type: rabbitmq
version: "3.12"
memory: 1Gi
volume_size: 5
# Storage services
- name: files
type: minio
version: latest
memory: 1Gi
volume_size: 100
- name: ftp
type: sftp
version: latest
memory: 256Mi
volume_size: 50
settings:
username: ftpuser
password: secure_ftp_password
# Worker services
- name: default-worker
type: worker
memory: 1Gi
command: php artisan queue:work --queue=default --tries=3
- name: email-worker
type: worker
memory: 512Mi
command: php artisan queue:work --queue=emails --tries=5
- name: heavy-worker
type: worker
memory: 2Gi
command: php artisan queue:work --queue=heavy --timeout=3600
container_services:
- name: pdf-generator
type: gotenberg
version: "8"
memory: 1Gi
settings:
LOG_LEVEL: info
DEFAULT_WAIT_TIMEOUT: "60"
- name: browser
type: chrome-headless
version: stable
memory: 2Gi
- name: analytics
type: clickhouse
version: "23.8"
memory: 4Gi
volume_size: 100
- name: search
type: meilisearch
version: "1.5"
memory: 1Gi
volume_size: 5
Applying your configuration
You can apply your infrastructure configuration using the API. Send a POST request with your YAML content:
curl -X POST https://api.ploi.cloud/api/v1/infrastructure/apply \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/yaml" \
--data-binary @your-infrastructure.yaml
Dry run mode
Preview what changes would be made without actually applying them:
curl -X POST "https://api.ploi.cloud/api/v1/infrastructure/apply?dry_run=true" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/yaml" \
--data-binary @your-infrastructure.yaml
Manual deployment
By default, changes are automatically deployed. To apply changes without triggering a deployment:
curl -X POST "https://api.ploi.cloud/api/v1/infrastructure/apply?auto_deploy=false" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/yaml" \
--data-binary @your-infrastructure.yaml
Response format
The API returns details about what was changed:
{
"success": true,
"team": "Your Team",
"dry_run": false,
"changes": [
"Application 'production-app' created",
"Domain 'app.example.com' added",
"Secret 'APP_KEY' created",
"Service 'database' (mysql) created"
],
"structured_changes": {
"application": { "action": "created", "name": "production-app" },
"domains": [{ "action": "created", "domain": "app.example.com" }],
"secrets": [{ "action": "created", "key": "APP_KEY" }],
"services": [{ "action": "created", "name": "database", "type": "mysql" }]
},
"errors": [],
"needs_deployment": true,
"auto_deploy_enabled": true,
"deployment_id": 456
}
Important notes
- The application name must be unique within your team
- Some fields like application type cannot be changed after creation
- Services and volumes are automatically connected to your application
- All resources are managed together - updating the configuration will update all resources
- Removing items from the configuration will not delete them (for safety)
For complete API documentation and additional options, see the API reference.