Getting Started¶
Doco-CD runs on your Docker host. It watches Git repositories for changes and uses Docker to deploy or update the Compose applications described in them. Doco-CD runs in its own container, separate from the containers of the applications it deploys.
This is how it works:
- You keep your Compose files, plus a small
.doco-cd.ymlfile, in a Git repository. - You push a change. Doco-CD notices it by polling the repository or through a webhook from your Git provider.
- Doco-CD pulls the repository and updates your applications on the Docker host, much like running
docker compose up -dyourself.
Choose how to run Doco-CD¶
Pick one option and follow only its steps. Doco-CD deploys your applications the same way in both setups. The difference is how you manage Doco-CD itself:
| Option A: self-updating (recommended for a new install) | Option B: standalone | |
|---|---|---|
| Where Doco-CD's own Compose file lives | In your deployment repository | On the Docker host |
| How you update Doco-CD | Commit a new image version. Doco-CD replaces itself. | Run docker compose pull and docker compose up -d. |
| Setup effort | Edit two files and run a one-time bootstrap script | Download and edit one Compose file |
| Switching to the other option later | Not needed | Requires a migration |
Follow Option A or Option B below. Run the bootstrap in Option A only on a host where Doco-CD is not installed yet. To convert an existing installation to self-updating, follow the migration steps.
Short version of Option A: Self-updating install (recommended)
- Create an empty Git repository on your Git provider and clone it to your computer.
- Copy the contents of
examples/self-updating/infra-repointo the repository. - Open
doco-cd/compose.yamlin the repository. SeturlinPOLL_CONFIGto your repository URL, and setTZto your time zone. - Commit and push the repository to your Git provider.
- For a private repository, also complete step 3 of Option A.
- On the Docker host, download
bootstrap.shto a folder outside the repository, for example your home folder. The script is not part of your repository. - In
bootstrap.sh, setREPO_URLto the same repository URL as in step 3. - On the Docker host, make the script executable and run it once:
chmod +x bootstrap.sh && ./bootstrap.sh. - Check that the Doco-CD container runs with
docker ps.
Do not run bootstrap.sh again after this. Doco-CD updates itself from the repository.
The rest of this page explains each step in detail.
Before you start¶
What you need¶
-
A Docker host with Docker Engine and the Docker Compose plugin. Check with
docker infomust print details about the server. If it reportspermission denied, run the commands withsudoor add your user to thedockergroup. -
A Git repository that holds your Compose files. It can be public or private and hosted by GitHub, GitLab, Gitea, Forgejo, or another Git server. A local repository that you mount into the container also works. You need permission to push to it.
-
For configuration options see App Settings and Deploy Settings.
Terms used in this guide¶
- Deployment repository: The Git repository that holds your Compose files and the
.doco-cd.ymlfile. It can be a dedicated repository or the repository that also holds the source code of your application. - Deployment configuration: The
.doco-cd.ymlfile in the root of the deployment repository. It tells Doco-CD which applications to deploy and where their Compose files are. - Compose project: One application started with Docker Compose. Doco-CD deploys each entry of the deployment configuration as one Compose project.
- See also the Core Concepts page for an overview of Doco-CD's architecture and terminology.
Treat the Docker host and deployment repositories as trusted
The default setup mounts /var/run/docker.sock, which gives Doco-CD broad control over the Docker host. A deployment runs the Compose configuration and images specified in its Git repository, so only let repositories you trust trigger deployments on this host.
Limit Docker API access with a proxy
You can put a Docker socket proxy between Doco-CD and Docker to limit which API endpoints it can call. See Docker API Permissions for the required endpoints and a proxy example. For self-updating Doco-CD, keep the proxy in a separate Compose project; see Self-Updating.
Choose a deployment trigger¶
Polling and webhooks are both supported. Choose either one or use both. If you are not sure, start with polling. It needs no network setup, and you can add webhooks later.
| Method | How it works | What the home network needs |
|---|---|---|
| Polling | Doco-CD checks each configured repository on an interval (3 minutes by default). | No inbound connection to Doco-CD. Remote repositories need outbound access; local repositories can be mounted into the container. |
| Webhooks | Your Git provider sends Doco-CD a request when a change is pushed. | The provider must be able to reach Doco-CD over HTTP/HTTPS. A cloud provider such as GitHub usually needs a route from the internet. |
Webhooks¶
Webhooks can start a deployment shortly after a push. Set a strong WEBHOOK_SECRET, configure the webhook in your Git provider, and route its HTTPS request to Doco-CD's /v1/webhook endpoint. Put the endpoint behind a TLS-enabled reverse proxy (e.g. Traefik or Caddy). Do not expose the metrics port or send the secret over plain HTTP.
See Setup Webhook for provider-specific steps and Webhook Listener for endpoint details.
Polling¶
Polling checks repositories at a configured interval and does not require Doco-CD to be reachable from the Git provider. Doco-CD runs the first poll right after it starts. This guide uses an interval. Cron schedules are an advanced option. A scheduled poll waits until its next scheduled time, so it does not deploy anything right after startup.
If your repository is on the Docker host, Doco-CD can poll a local Git repository mounted read-only into its container; see Polling Local Filesystem Repositories.
The poll configuration contains the repository URL and an optional branch and interval:
- url: https://github.com/your-user/your-deploy-repo.git
reference: main # (1)!
interval: 3m # (2)!
- The branch (or tag) to deploy from. Doco-CD uses
mainby default. - The interval can be a Go duration (
3m) or an integer value in seconds (180). The minimum is 10 seconds.
See Poll Settings for POLL_CONFIG, POLL_CONFIG_FILE, scheduled polling, and other options.
Install Doco-CD¶
Option A: Self-updating install¶
Use this option on a new host. It uses a one-time bootstrap script to create the first Doco-CD container from a Git repository, with the labels Doco-CD needs to recognize and update its own stack. After that, you manage Doco-CD like any other application: change its Compose file in Git and push.
This option builds on the self-updating example. See the Bootstrap section of the Self-Updating guide for background.
-
Create your deployment repository from the example. Download the example and copy its files:
git clone --depth 1 https://github.com/kimdre/doco-cd.git doco-cd-src cp -r doco-cd-src/examples/self-updating/infra-repo your-deploy-repo cp doco-cd-src/examples/self-updating/bootstrap.sh bootstrap.shyour-deploy-repo/becomes your deployment repository. It contains:.doco-cd.ymlwith two entries: one for Doco-CD itself and one for a sample application.doco-cd/compose.yaml, the Compose file of Doco-CD itself.app/compose.yaml, a sample Nginx application.
bootstrap.shis a one-time script. Keep it outside the repository and run it later on the Docker host. You can delete thedoco-cd-srcfolder after the copy.Now create an empty repository at your Git provider and note its clone URL. Do not add a README, license, or
.gitignoreyet. The first commit comes from the files you copied. If the provider creates a commit first, Git treats it as a separate history and rejects the initial push. You can add a README after the first push. -
Set your values. Edit these settings:
File Setting Set it to bootstrap.shREPO_URLThe clone URL of your deployment repository bootstrap.shreference: maininsidePOLL_CONFIGYour branch, if it is not mainyour-deploy-repo/doco-cd/compose.yamlurlandreferenceinsidePOLL_CONFIGThe same URL and branch as in bootstrap.shyour-deploy-repo/doco-cd/compose.yamlintervalinsidePOLL_CONFIGThe example uses 300 seconds (5 minutes). Change it if you prefer another interval (minimum 10 seconds). your-deploy-repo/doco-cd/compose.yamlTZYour time zone, for example Europe/BerlinLeave the rest as it is. The example already pins the Doco-CD version with a digest in both files. Keep
SELF_UPDATE_ENABLED, the restart policy, and the healthcheck, because self-updates need them. Do not addcontainer_nameor host ports. They force a short restart for each update instead of a zero-downtime update; see self-update strategies. -
Required for private repositories: give Doco-CD a Git access token. A public repository needs no token (but it is still recommended). Both the one-time bootstrap container and the Doco-CD container that keeps running need the token. Keep the token out of the repository. Save it in a file on the Docker host that only root can read:
sudo mkdir -p /opt/doco-cd echo 'your_read_only_token' | sudo tee /opt/doco-cd/git-access-token > /dev/null sudo chmod 600 /opt/doco-cd/git-access-tokenThen uncomment the three
git_access_tokenblocks marked inyour-deploy-repo/doco-cd/compose.yaml. They mount the file into the container and setGIT_ACCESS_TOKEN_FILE. The bootstrap script reads the token from your shell, so export it before you run the script in step 5:SSH keys and GitHub Apps need their credentials configured in both places as well. See Git authentication and the example's notes on private repositories. To keep the token itself in Git, encrypted with SOPS or fetched from an external secret provider, see Setup Git Access Token.
-
Push the repository.
cd your-deploy-repo git init -b main git add . git commit -m "Add Doco-CD and a sample app" git remote add origin https://github.com/your-user/your-deploy-repo.git git push -u origin mainUse the clone URL from step 1. Git asks for your own credentials here. These are separate from Doco-CD's read-only token.
-
Run the bootstrap on the Docker host.
The script creates the data volume and starts a temporary container. That container clones your repository, deploys Doco-CD and the sample application, and then exits. If Docker needs
sudoon your host, runsudo --preserve-env=GIT_ACCESS_TOKEN ./bootstrap.shinstead. If the script exits with an error, fix the reported problem and run it again. -
Check the result.
docker pslists a Doco-CD container (its name containsdoco-cd) and the sample app container.curlreturnsHTTP/1.1 200 OKand the Nginx welcome page. The sample app is bound to the loopback address, so it is reachable only from the Docker host itself. To read the Doco-CD logs, find the container name and follow its log:A healthy start shows
polling repositoryfollowed byjob completed successfully. Press Ctrl+C to stop following the log. This does not stop Doco-CD.
From now on, do not run the bootstrap script again. To update Doco-CD, change the image tag and digest in doco-cd/compose.yaml and push. A tool such as Renovate can open these version updates for you. To deploy your own applications, replace the sample app in app/ or add more entries; see Deploy your own applications.
Webhooks with the self-updating install
The example uses polling. To add webhooks, set WEBHOOK_SECRET_FILE in doco-cd/compose.yaml the same way as the token file, and route the webhook requests through a reverse proxy that shares a Docker network with Doco-CD. If you publish a host port for Doco-CD instead, each Doco-CD update causes a short restart; see self-update strategies.
Do not run the bootstrap on a host that already has Doco-CD running.
Migrate the existing instance instead.
Option B: Standalone install¶
Use this option if you prefer to keep Doco-CD's Compose file on the Docker host and update Doco-CD yourself. In this setup, Doco-CD does not update its own Compose project.
If you want self-updating later, follow the migration guide. Do not run the bootstrap.
Step 1: Create the deployment repository¶
Create an empty repository on your Git provider and clone it on any machine that has Git. Do this before you start Doco-CD. Doco-CD polls the repository as soon as it starts, so an empty repository makes the first poll fail.
Add a .doco-cd.yml file to the root of the repository:
- The name of the Compose project. Use lowercase letters, numbers, hyphens, or underscores, and make it unique on the Docker host. Choose it with care. Docker cannot rename a project later; see Known Limitations.
By default, Doco-CD looks for compose.yaml, compose.yml, docker-compose.yml, or docker-compose.yaml in the root of the repository. If your Compose file is in a subdirectory, add working_dir: <directory>. To use other file names, add compose_files. See Deploy Settings for all options. The repository then looks like this:
For a simple test deployment, compose.yaml can contain:
If Docker Compose is installed on this machine, check the Compose file with docker compose config --quiet. Then commit and push both files:
git add .doco-cd.yml compose.yaml
git commit -m "Add Doco-CD deployment config"
git branch -M main
git push -u origin main
Git asks for your own credentials here. These are separate from Doco-CD's read-only token. Doco-CD polls the branch named in POLL_CONFIG (the sample uses main), so push to that branch.
Step 2: Install Doco-CD on the Docker host¶
Create a directory on the Docker host and save the sample Compose file there. This file lives on the host. Do not put it in your deployment repository.
mkdir -p ~/doco-cd
cd ~/doco-cd
curl -fsSL https://raw.githubusercontent.com/kimdre/doco-cd/main/docker-compose.yml -o docker-compose.yml
The file defines Doco-CD itself, its Docker socket access, and a named volume for persistent data.
Full Doco-CD Compose file
The downloaded file is the same template shown here. Its polling, webhook, and port settings are commented out until you choose to enable them.
services:
app:
# For zero-downtime scale_out self-updates, omit container_name and host
# ports. The auto strategy can use applier instead, with a brief restart.
container_name: doco-cd
# You can also pin to a specific tag (version)
# Available tags can be found here: https://github.com/kimdre/doco-cd/pkgs/container/doco-cd
image: ghcr.io/kimdre/doco-cd:latest
restart: unless-stopped
# Polling needs no published ports. For webhooks, publish HTTP_PORT only
# to a trusted HTTPS reverse proxy. This loopback example assumes the proxy
# runs on the Docker host. Keep metrics private if publishing them.
# ports:
# - "127.0.0.1:8080:80"
# - "127.0.0.1:9120:9120"
# For all available environment variables and explanations, see https://doco.cd/latest/App-Settings/
environment:
# Use an IANA time zone, for example Etc/UTC or Europe/Berlin.
TZ: Europe/Berlin
GIT_ACCESS_TOKEN: ${GIT_ACCESS_TOKEN:-}
# Add WEBHOOK_SECRET to .env and uncomment to enable webhooks:
# WEBHOOK_SECRET: ${WEBHOOK_SECRET:?Set WEBHOOK_SECRET in .env}
# Uncomment and replace the URL to enable polling:
# POLL_CONFIG: |
# - url: https://github.com/your-user/your-deploy-repo.git
# reference: main
# interval: 180
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# The data volume (left side) can also be replaced with a bind mount to a local directory, for example:
# - ./data:/data
- data:/data
cap_drop:
- ALL
healthcheck: # runs the image's built-in /healthcheck command
start_period: 15s
interval: 30s
timeout: 5s
retries: 3
volumes:
data:
Edit docker-compose.yml, set TZ to your preferred time zone, and enable the trigger you chose:
- For polling, uncomment
POLL_CONFIGand replace the sample URL and branch with your deployment repository. - For webhooks, add
WEBHOOK_SECRETto.env, uncomment its environment setting and the HTTP port mapping, then configure your HTTPS reverse proxy and Git provider. The sample's loopback port mapping is for a proxy running directly on the Docker host. A proxy in another container needs a shared Docker network. - To use both methods, enable both settings.
The sample publishes no Doco-CD ports by default. Polling needs none. Publish Doco-CD's HTTP endpoint only when a webhook or API integration needs it, and expose metrics only on a trusted network if you use them. The ports of your applications are separate. They are set in the Compose files of your deployment repository.
If you need a .env file for credentials, create it now as described in Set up Git authentication. Then check the configuration and start Doco-CD:
docker compose config --quiet
docker compose up -d
docker compose ps
docker compose logs --tail=100 -f app
The -f option follows new log messages. Press Ctrl+C to return to the shell without stopping Doco-CD.
Step 3: Check that it works¶
docker compose psshows theappservice ashealthywithin about a minute. It first showsstarting.- The log shows
polling repositoryfollowed byjob completed successfully. docker compose lslists the projectmy-appas running.- On the Docker host,
curl -i http://127.0.0.1:8080returnsHTTP/1.1 200 OKand the details of the whoami service.
Polling deploys on its next check. Doco-CD also polls right after it starts, so the application is usually up within a minute or two. Later pushes are picked up within the poll interval (3 minutes with the sample). A webhook starts a deployment after the provider sends the configured event.
Update Doco-CD¶
If you use the sample's latest image, pull the new image and recreate the container from ~/doco-cd:
If you pinned a version instead, change the image tag first in the compose file, then run the same commands. The container restarts with the new version.
Recommended: Use a pinned version to control upgrades
It is safer to pin a specific version of Doco-CD instead of using latest. This avoids unexpected changes when a new image is published. Replace the latest tag with a release version without the leading v (for example, 0.125.1).
See the available container tags.
Notes for Podman users¶
If you are using Podman instead of Docker, you may need to adjust the Compose file to use the Podman socket instead of the Docker socket:
services:
app:
...
volumes:
- - /var/run/docker.sock:/var/run/docker.sock
+ - /var/run/podman/podman.sock:/var/run/docker.sock
...
Set up Git authentication¶
Public repositories can be cloned without credentials. For private repositories:
- For an
https://URL, use a token with read access to repository contents. See Setup Access Token for provider-specific permissions and configuration. - For an SSH URL such as
git@github.com:owner/repo.git, configure a deploy key or another SSH key. See Setup SSH Key. - For GitHub, a GitHub App is another authentication option; see GitHub App authentication.
Never commit plaintext credentials to Git. See Using encrypted secrets and Fetching secrets from external providers for alternatives.
How you pass the credentials to Doco-CD depends on the option you chose:
- Option A: Use a token file as described in step 3 of Option A.
-
Option B: The sample Compose file reads
GIT_ACCESS_TOKENandWEBHOOK_SECRETfrom a.envfile next to it. Create that file with only the values you need:.env# For a private HTTPS repository: GIT_ACCESS_TOKEN=your_read_only_token # For webhooks: WEBHOOK_SECRET=your_random_webhook_secretGenerate a secure webhook secret with
openssl rand -base64 32. On Linux, runchmod 600 .envso other local users cannot read it. If you use SSH, follow the SSH key setup instead.
This .env file is only for Doco-CD itself
It sits next to Doco-CD's own Compose file on the Docker host. It is not the .env file that Doco-CD can read from your deployment repository for your applications.
See Git Settings for per-domain credentials and other authentication options.
Troubleshooting the first deployment¶
| Symptom | What to check |
|---|---|
| Nothing happens after a push | For polling, check the repository URL, branch, and interval in POLL_CONFIG, then wait for the next interval. For webhooks, check the provider's delivery history and confirm the HTTPS route reaches /v1/webhook. |
| Repository clone or authentication fails | Confirm the repository is reachable from the Docker host. For a private HTTPS repository, check that the token can read repository contents and that Doco-CD received it (Option A: the token file; Option B: .env). For SSH, follow the SSH key setup. |
The log says configuration file not found in repository | Confirm .doco-cd.yml is in the root of the repository and that you pushed it to the branch Doco-CD polls. If your Compose file is in a subdirectory, check that working_dir names it relative to the repository root. |
| Compose reports an error or a port is already in use | Run docker compose config --quiet in your deployment repository to check its Compose files. Resolve any host port conflict in the application's Compose file. Doco-CD's own ports are separate from the ports of your applications. |
The Doco-CD container restarts or stays unhealthy | Read its log. Doco-CD checks its settings at startup and names the setting it cannot use, for example POLL_CONFIG with invalid YAML, or both GIT_ACCESS_TOKEN and GIT_ACCESS_TOKEN_FILE set. |
| The bootstrap script fails (Option A) | Read the error that the script prints. Check the repository URL, the branch, and the token. Fix the cause and run the script again. |
For more detail in the log, set LOG_LEVEL: debug in Doco-CD's environment. See App Settings for all settings.
Deploy your own applications¶
Once the first deployment works, move your own applications into the deployment repository.
Keep persistent data out of the repository folder
Doco-CD deploys every revision from its own copy of the repository. Data that an application writes into a relative bind mount such as ./data:/data is lost when the next revision is deployed. Use named volumes or absolute host paths for data that must stay, for example /srv/my-app/config:/config. See Artifact Storage.
- Add more applications: Put each application in its own directory with its own Compose file. Then list them in
.doco-cd.ymlas separate YAML documents divided by---, or let Doco-CD find them with auto-discovery. See Multiple service deployments and Auto-Discovery. - Move an application that is already running: Read Migrating from Docker Compose first. It explains how to keep project names, volumes, and bind mounts.
- Keep secrets out of Git: Do not commit passwords or API keys in plaintext. Use SOPS encryption or external secrets.
- Remove an application: Deleting its files from Git does not remove its containers. Use the destroy settings.
See Deploy Settings for all deployment options and Core Concepts to learn how Doco-CD works.
Full working examples
The examples/ directory includes a single repository deployed to one environment, a single repository deployed to two environments, a self-updating Doco-CD instance, and a central deployments repository for many applications and Docker hosts. The single-repo example is a fuller reference; it includes Caddy and expects you to adapt its sample domain and ports.
More information¶
Git servers and authentication¶
Doco-CD works with GitHub, GitLab, Gitea, Forgejo, and other Git remotes. A hosting forge is not required; see Using a plain Git server. For all authentication options, see Git Settings.
If the clone URL advertised by your Git server is not reachable from the Doco-CD container, see Source URL Rewrites.
Deploying to multiple Docker hosts¶
Use Docker Contexts to deploy to multiple independent Docker hosts without requiring Docker Swarm. For a Swarm deployment, see Swarm Mode.
Migrating an existing Compose project¶
See Migrating from Docker Compose before adopting a stack that is already running on the host.
Using encrypted secrets¶
Doco-CD supports encrypting sensitive data in Git with SOPS. See Encryption for setup details.
Fetching secrets from external providers¶
Doco-CD supports external secret providers such as OpenBao, AWS Secrets Manager, Azure Key Vault, Bitwarden, and many more. See External Secrets for the full list and setup instructions.
Pulling images from a private registry¶
If you need to pull images from a private registry, see Container Registry Authentication.
Self-updating Doco-CD¶
The Self-Updating guide covers bootstrap, requirements, update strategies, migration of existing instances, and the older two-instance alternative.
Scheduling and notifications¶
See Job Scheduling for scheduled jobs, Poll Settings for cron-based polling, and Sync Windows for restricting when deployments can run. Doco-CD can also send notifications about deployment events.
REST API and Prometheus metrics¶
Doco-CD provides a REST API and Prometheus metrics for integrations and monitoring. Keep these endpoints private unless you specifically need to expose them.