Creating a dynamic compose file
In Runtipi version v3.2.0
we added dynamic compose, a simplified and custom version of the docker-compose.yml
file that allows for more control on how apps get deployed. For example, you can choose to only use the reverse proxy or only use ports. It also allows extra features like multiple appstores.
Here is an example docker-compose.json
file for a simple app like Nginx:
{
"services": [
{
"name": "nginx",
"image": "nginx",
"internalPort": 80,
"isMain": true
}
]
}
And that’s it, with just a few lines of config you can deploy an nginx app.
Creating your first dynamic compose file
Let’s see how easy it is to create the docker-compose.json
file.
Creating the file and enabling dynamic compose
First create the docker-compose.json
next to the docker-compose.yml
file in your app folder. Then edit the app’s config.json
and add this configuration line at the end:
"dynamic_config": true
Defining the services
Now add your services
array which defines all your services:
{
"services": []
}
The services
key is the same as in the docker-compose.yml
. Inside this array you can add multiple apps.
Adding a service
Let’s add a service called myapp
:
{
"services": [
{
"name": "myapp"
}
]
}
The name
key defines both the service name and container name.
Adding an image
Add your Docker image. For this example we’ll use myapp:latest
:
{
"services": [
{
"name": "app",
"image": "myapp:latest"
}
]
}
Exposing the UI
If your service exposes a web UI, add the port and main service configuration:
{
"services": [
{
"name": "myapp",
"image": "myapp:latest",
"internalPort": 80,
"isMain": true
}
]
}
The internalPort
specifies your app’s port, and isMain
indicates where the traefik labels should go. Traefik labels should always be on the part of the app that exposes the UI.
Adding volumes
To store app data, you can bind mount directories. For example, to mount ${APP_DATA_DIR}/data/myapp
to /data
with read-write permissions:
{
"services": [
{
"name": "myapp",
"image": "myapp:latest",
"internalPort": 80,
"isMain": true,
"volumes": [
{
"hostPath": "${APP_DATA_DIR}/data/myapp",
"containerPath": "data",
"readOnly": false
}
]
}
]
}
The volumes
key is an array where you can define multiple volume mounts.
Adding environment variables
Environment variables can be added easily using this format:
{
"services": [
{
"name": "myapp",
"image": "myapp:latest",
"internalPort": 80,
"isMain": true,
"volumes": [
{
"hostPath": "${APP_DATA_DIR}/data/myapp",
"containerPath": "data",
"readOnly": false
}
],
"environment": {
"FOO": "bar",
"PASSWORD": "${MYAPP_PASSWORD}"
}
}
]
}
You can add as many environment variables as needed and use values from form fields as you normally would.
Adding multiple ports
Many apps require multiple ports for features like APIs or setup UIs. Add additional ports like this:
{
"services": [
{
"name": "myapp",
"image": "myapp:latest",
"internalPort": 80,
"isMain": true,
"volumes": [
{
"hostPath": "${APP_DATA_DIR}/data/myapp",
"containerPath": "data",
"readOnly": false
}
],
"environment": {
"FOO": "bar",
"PASSWORD": "${MYAPP_PASSWORD}"
},
"addPorts": [
{
"containerPort": 8080,
"hostPort": 8080,
"tcp": true
},
{
"containerPort": 25565,
"hostPort": 25565,
"udp": true
}
]
}
]
}
Create an addPorts
array and define your container and host ports. Specify if the port is UDP or TCP - if not defined, TCP is assumed. For ports that need both TCP and UDP:
"addPorts": [
{
"containerPort": 8080,
"hostPort": 8080,
"tcp": true
},
{
"containerPort": 8080,
"hostPort": 8080,
"udp": true
}
]
Adding a healthcheck
Add container health monitoring with a healthcheck:
{
"services": [
{
"name": "myapp",
"image": "myapp:latest",
"internalPort": 80,
"isMain": true,
"volumes": [
{
"hostPath": "${APP_DATA_DIR}/data/myapp",
"containerPath": "data",
"readOnly": false
}
],
"environment": {
"FOO": "bar",
"PASSWORD": "${MYAPP_PASSWORD}"
},
"addPorts": [
{
"containerPort": 8080,
"hostPort": 8080,
"tcp": true
},
{
"containerPort": 25565,
"hostPort": 25565,
"udp": true
}
],
"healthCheck": {
"test": "curl --fail http://localhost || exit 1",
"retries": 3,
"interval": "30s",
"timeout": "10s"
}
}
]
}
Adding dependencies
If your service depends on other services (like a database), add the dependsOn
key:
{
"services": [
{
"name": "myapp",
"image": "myapp:latest",
"internalPort": 80,
"isMain": true,
"volumes": [
{
"hostPath": "${APP_DATA_DIR}/data/myapp",
"containerPath": "data",
"readOnly": false
}
],
"environment": {
"FOO": "bar",
"PASSWORD": "${MYAPP_PASSWORD}"
},
"addPorts": [
{
"containerPort": 8080,
"hostPort": 8080,
"tcp": true
},
{
"containerPort": 25565,
"hostPort": 25565,
"udp": true
}
],
"healthCheck": {
"test": "curl --fail http://localhost || exit 1",
"retries": 3,
"interval": "30s",
"timeout": "10s"
},
"dependsOn": {
"service1": {
"condition": "service_healthy"
}
}
}
]
}
For simple dependencies without conditions, you can use the shorter format:
"dependsOn": "service1"
Other configuration options
You can also add these common options:
Custom command:
"command": "/my/app"
Custom network mode:
"networkMode": "host"
Process limits:
"ulimits": {
"nproc": {
"soft": 10,
"hard": 20
},
"nofile": {
"soft": 20,
"hard": 30
}
}
Extra hosts:
"extraHosts": [
"somehost:someotherhost"
]
Try it out
You can validate your dynamic compose configuration using the validator below:
For a complete reference of all available configuration options, see the Dynamic Compose Reference documentation.
Docker Compose to Dynamic Config Converter
Converting an existing docker-compose.yml
file to Runtipi’s dynamic compose format can be time-consuming and error-prone. We’ve created a tool to help you automatically convert your Docker Compose files to the dynamic compose format.
Docker Compose YAML
Dynamic Compose Output
The converter works for most cases, but please review the converted configuration to ensure it meets your needs. Some advanced features may not be fully supported.