Docker Compose File Management#
Dokploy manages Docker Compose files through a pipeline in packages/server/src/utils/docker/ and packages/server/src/utils/providers/. The pipeline covers four phases: source acquisition (clone or create), loading (local filesystem or SSH remote), transformation (suffix randomization, domain/network injection), and serialization back to disk.
Source Types and File Acquisition#
The Compose record carries a sourceType field with six possible values: github, gitlab, bitbucket, gitea, git, and raw. cloneCompose() in domain.ts dispatches to the correct provider based on this value.
sourceType | Provider Function | Auth Mechanism |
|---|---|---|
github | cloneGithubRepository() | OAuth token |
gitlab | cloneGitlabRepository() | OAuth2 / HTTP Basic |
bitbucket | cloneBitbucketRepository() | API token / app password |
gitea | cloneGiteaRepository() | OAuth2 with token refresh |
git | cloneGitRepository() | SSH key or HTTPS |
raw | getCreateComposeFileCommand() | N/A (inline content) |
raw source: getCreateComposeFileCommand() base64-encodes the stored composeFile string via encodeBase64(), then generates a bash snippet that decodes it and writes docker-compose.yml to disk:
echo "<base64>" | base64 -d > "<outputPath>/docker-compose.yml"
This avoids shell quoting issues when file content is passed through SSH commands.
git source: cloneGitRepository() supports both HTTPS and SSH URLs. For SSH, it writes the private key to /tmp/id_rsa with chmod 600 and sets GIT_SSH_COMMAND to point git at that key and the known_hosts file under SSH_PATH. SSH URLs without a configured key fail fast with an explicit error.
File Paths: Local vs. Remote#
paths(isServer) determines the base directory:
- Local (development):
.docker/relative tocwd() - Remote / production:
/etc/dokploy/
COMPOSE_PATH resolves to <BASE_PATH>/compose. The full on-disk path for a compose app is:
<COMPOSE_PATH>/<appName>/code/<composePath>
For sourceType === "raw", composePath is always docker-compose.yml .
Loading: Local vs. SSH Remote#
loadDockerCompose() reads the file from the local filesystem with readFileSync and parses YAML with maxAliasCount: 10000.
loadDockerComposeRemote() runs cat <path> over SSH via execAsyncRemote(serverId, ...), then parses the stdout. Any stderr output or exception causes a null return. The caller selects the right loader based on whether compose.serverId is set .
Transformation Pipeline#
After loading, the spec is optionally transformed before domain labels are injected.
Suffix randomization — when compose.randomize is true, randomizeSpecificationFile() applies a random 4-byte hex suffix to every service name, volume, network, config, and secret via five dedicated helpers . This prevents resource-name collisions when multiple instances of the same compose run on the same Docker host.
Isolated deployment — when compose.isolatedDeployment is true, randomizeDeployableSpecificationFile() prefixes names with the app name instead of a random hash. The compose is deployed into an isolated network (no dokploy-network injection) .
Domain/network injection — addDomainToCompose() iterates over attached Domain records and injects Traefik labels per service. For non-isolated deployments it also calls addDokployNetworkToService() and addDokployNetworkToRoot() to wire dokploy-network (external) into the spec.
Label placement depends on composeType :
docker-compose→ labels go onservices[name].labelsstack→ labels go onservices[name].deploy.labels
Serialization#
Modified specs are serialized back to YAML with stringify(spec, { lineWidth: 1000 }) to avoid unwanted line-wrapping. For writes that must happen on a remote server, the serialized string is base64-encoded and piped through base64 -d > — the same pattern used for raw file creation . For local writes, writeComposeFile() uses fs.writeFileSync directly.
Key Entry Points#
| Function | File | Purpose |
|---|---|---|
cloneCompose() | domain.ts:23 | Dispatch clone by sourceType |
getComposePath() | domain.ts:45 | Resolve on-disk path |
loadDockerCompose() | domain.ts:59 | Load from local FS |
loadDockerComposeRemote() | domain.ts:74 | Load via SSH |
addDomainToCompose() | domain.ts:134 | Transform + inject domains |
writeDomainsToCompose() | domain.ts:109 | Serialize + write back |
randomizeComposeFile() | compose.ts:15 | Suffix-randomize full spec |
getCreateComposeFileCommand() | raw.ts:6 | Create file from raw content |
encodeBase64() | utils.ts:705 | UTF-8 → base64 for shell safety |
paths() | constants/index.ts:96 | Resolve base paths |