Self-hosted service
ajnart/dcm avatar
ajnart/dcm

DCM (Docker Compose Maker): a self-hosted picker for home server compose files

DockerComposeMaker (DCM) is a self-hostable website to help you pick and create a docker-compose.yml file for your home server. Discover new containers, discover and share a config in a couple of clicks!

1,447 stars57 forksTypeScriptAGPL-3.0

At a glance

What is it?
DCM is a Next.js web app that lets you select curated self-hosted containers and export a docker-compose.yaml plus matching .env. It runs from a single Docker image, and its value depends entirely on the catalogue it ships.
Who is it for?
DCM is worth adopting if you are standing up a first home server stack and want a starting point that already wires ${PUID}, ${PGID} and ${TZ} into every service, or if you run a small stack and keep mistyping volume paths. Skip it if your stack depends on images the catalogue does not carry, if you need generated files that are reproducible from a pinned source, or if you would rather write compose by hand and keep full control.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 15 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The copy-paste problem DCM is built around

Every self-hosted application ships its own compose example, and those examples disagree with each other. One uses a bind mount under /opt, another uses a named volume, a third hardcodes PUID=1000. Assembling six of them into one file means six rounds of reading documentation and six chances to mistype a path. DCM targets exactly that step. The README describes it as a tool that helps you create docker-compose.yaml files for self-hosted applications, with the user selecting from a curated list and generating a ready-to-use configuration in a few clicks. The audience is the home server operator who knows what Jellyfin or Sonarr is but does not want to re-derive the volume layout for each one. It is not aimed at teams running orchestrated workloads, and nothing in the repository suggests Kubernetes or Swarm output. The whole product is a browser interface that emits two text files.

What happens between selecting a container and copying the compose file

The repository layout tells most of the story. The top level holds app/, components/, containers/, functions/, hooks/, lib/ and tools/, with a containers/ directory that is separate from the app code. That separation matters: the catalogue of supported applications lives as data, and the tests/ directory contains validate-all-containers.test.ts alongside validate-compose.test.ts and templates.test.ts. The package.json exposes these as bun run test:containers, bun run test:compose and bun run test:templates, so a malformed container definition or a template that produces invalid compose is meant to fail CI before it reaches the site.

The runtime is a static Next.js export. The build script is next build, and start is serve out -p 7576, which means the deployed artifact is a folder of static files served by the serve package. The Dockerfile confirms this: it copies out/ into /app, installs serve globally, sets DISABLE_TELEMETRY=true and runs serve /app -p 7576. There is no database and no server-side API in the container image. Generation happens in the browser, which is why the self-hosted version can run without any backend at all. The wrangler.toml plus the deploy script (next build, then wrangler pages functions build, then wrangler pages deploy) show the hosted version at compose.ajnart.dev is deployed to Cloudflare Pages with functions, and the README notes the online version includes analytics while the self-hosted one does not.

Running DCM with Docker on port 7576

The README gives a single-command path. The image is published to the GitHub Container Registry as ghcr.io/ajnart/dcm and is built for linux/amd64, linux/arm64 and linux/arm/v7, so a Raspberry Pi is covered.

bash
docker run -p 7576:7576 --name dcm --rm ghcr.io/ajnart/dcm

After that, the README says to open http://localhost:7576 in a browser. You should see the container picker, not a login page; DCM has no authentication layer in the documented setup, which is a point to weigh if the host is reachable from outside your network.

For a persistent setup, the README provides a compose file instead:

yaml
services:
  dcm:
    image: ghcr.io/ajnart/dcm
    container_name: dcm
    ports:
      - "7576:7576"
    restart: unless-stopped

Run docker-compose up -d and the service comes back after a reboot. Note there is no volume mount in this example, and none is needed: the container serves static files and holds no state. Your generated stacks live in your downloads folder, not in the DCM container.

If you want to build from source, the README requires Bun rather than npm, with an explicit warning that npm may cause longer install times and compatibility issues. The sequence is git clone, then bun install, then bun run build and bun start. The start script serves the out/ directory on port 7576, the same port as the container.

The generated file assumes variables you have to supply

The most consequential detail in the README is a warning, not a feature: all containers are configured to use environment variables like ${PUID}, ${PGID} and ${TZ}, and you must set them in your deployment or hit permission issues. That means the compose file DCM produces is deliberately incomplete. It is a template with holes, and the .env file it exports alongside is what fills them. The README states the downloaded .env contains all the environment variables referenced in the compose file and that both files must stay in the same directory when deploying.

This is a reasonable design, and it is also the most common way a DCM-generated stack fails on first run. If you paste only the compose content into Portainer, the variables resolve to nothing. The README calls this out directly: with Portainer Stacks you need to add the environment variables manually or upload the .env file, because Portainer does not automatically read the .env file in all configurations. If your UID and GID are not 1000, you have to know that before you deploy, and the README does not tell you how to find them.

Where DCM stops being the right tool

DCM is a generator, not a manager. Once you have copied the compose file, DCM has no role in updating, monitoring or restarting that stack. The README lists Portainer, Docker Desktop, Rancher, Yacht and plain command-line tools as deployment targets, which is an honest admission that the project is one step in a longer workflow. If what you actually want is to see and control running containers from a browser, DCM is the wrong layer entirely.

The catalogue is the other boundary. The README states the project is community-driven and invites contributions for tools that are not listed. That is a polite way of saying coverage is finite and depends on someone having submitted a definition. If your stack includes an application the catalogue does not carry, you are back to reading its documentation, and you will be merging a hand-written service into a generated file. There is also no documented mechanism for pinning a specific image tag per container, and the README does not document rollback of a generated configuration. A file you generated today is not reproducible tomorrow unless you keep the copy you downloaded; treat the exported .env and compose file as the artifact, not the DCM instance.

How DCM differs from Portainer and Dockge

Portainer and Dockge both assume you already have a compose file and want to run and observe it. They are control planes. DCM sits before that step and produces the file. The README's own Portainer instructions make the relationship concrete: you generate in DCM, then paste into Portainer's web editor as a stack, then deploy. The two are complementary rather than competing, and DCM's output is explicitly designed to be consumed by tools in that category.

The difference in approach is where the knowledge lives. Portainer and Dockge give you an editor and a runtime view with no opinion about what a Sonarr service should look like. DCM gives you a curated definition with defaults already chosen and no runtime view at all. That trade is the whole product. If you already know the correct volume layout for every service you run, DCM adds a translation step between you and the file. If you do not, it removes the documentation reading.

Licence and the cost of keeping up

The repository is licensed AGPL-3.0-only, and package.json marks the package as private. The AGPL matters if you plan to modify DCM and expose it to users over a network: that is the scenario the licence is written for, and it carries source-availability obligations. Running the published container as-is for your own home server is the ordinary case and is what the README documents. This is not legal advice; read the LICENSE file in the repository if you intend to fork and host a modified version.

The upgrade cost is low in one sense and non-zero in another. The container is stateless, so upgrading is pulling a new image and restarting; there is no migration, no schema, no data directory to back up. The last push to the repository was on 2026-08-27, and the only release listed is v1 from 2025-10-02, so versioning is coarse and there is no changelog trail to follow between releases. The real maintenance burden lands on your generated files. Because DCM does not manage what it produces, image updates for Jellyfin or Sonarr are your problem, handled by whatever tool you deployed into.

Editorial conclusion

DCM is worth adopting if you are standing up a first home server stack and want a starting point that already wires ${PUID}, ${PGID} and ${TZ} into every service, or if you run a small stack and keep mistyping volume paths. Skip it if your stack depends on images the catalogue does not carry, if you need generated files that are reproducible from a pinned source, or if you would rather write compose by hand and keep full control. Before committing, open the container list for the services you actually run, generate one stack, and diff the result against the compose file you already have; that single comparison tells you whether the curated defaults save you time or just add a translation step.

Frequently asked questions

What is DCM (Docker Compose Maker) and who is it for?

DCM is a self-hostable website that helps you pick and create a docker-compose.yml file for a home server. It is aimed at self-hosted operators who want a starting configuration without copying examples out of each application's documentation.

How do I run DCM with Docker Compose?

The README gives a compose file with the image ghcr.io/ajnart/dcm, container_name dcm, a 7576:7576 port mapping and restart: unless-stopped, started with docker-compose up -d. The same port is used by the single docker run command.

Does DCM replace Portainer or Dockge?

No. DCM generates the compose file and .env, while Portainer and Dockge run and observe the stack. The README walks through pasting DCM output into Portainer's web editor as a stack, which shows the two are used together.

Why does a DCM-generated compose file fail with permission errors?

The README warns that all containers are configured to use ${PUID}, ${PGID} and ${TZ}, and that you must set these in your deployment to avoid permission issues. The exported .env file carries those variables and must stay in the same directory as the compose file.

Can I build DCM from source with npm?

The README recommends Bun instead, warning that npm may result in longer installation times and potential compatibility issues. The documented source build is git clone, bun install, bun run build, bun start.

Official sources

  1. ajnart/dcm on GitHub
  2. License: AGPL-3.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ajnart-dcm.svg)](https://hysenlabs.com/projects/ajnart-dcm)