Docs menu

Docs · Deploy

Deploy a Docker Compose app

Updated · 9 min read

You have a compose.yaml, or a docker-compose.yml, that works on your laptop, and you want it online at an HTTPS address. On Pethost the file runs as written: pethost deploy in its folder builds the images, starts every service and gives the web service its address. Here Docker's own Compose quickstart goes online that way, in 28 seconds.

In short
  • One command: pethost deploy in the folder with compose.yaml, or the panel, or your AI agent.
  • The address: a published port that answers HTTP gets https://<project>.<you>.pethost.app. A service with no ports: stays private.
  • Nothing is converted: what Pethost will not run is refused before anything starts, with what to write instead.
  • Data and secrets: named volumes outlive every deploy and are backed up nightly. Secrets go into the project's .env.
  • The price: €9.99 a month for as many projects as fit. There is no free tier.

Deploy a Docker Compose app with one command

Step 1: Install pethost

On macOS and Linux:

curl -fsSL https://pethost.dev/install.sh | sh

On Windows, in PowerShell:

irm https://pethost.dev/install.ps1 | iex

You need a plan; the first deploy signs you in through your browser.

Step 2: Go to the folder that has compose.yaml

Here it is Docker's Compose quickstart, in a folder named counter: a Flask app that counts visits in Redis, its Dockerfile, and these two files:

compose.yaml
services:
  web:
    build: .
    ports:
      - "${APP_PORT}:5000"
    environment:
      - REDIS_HOST=${REDIS_HOST}
      - REDIS_PORT=${REDIS_PORT}

  redis:
    image: redis:alpine
.env
APP_PORT=8000
REDIS_HOST=redis
REDIS_PORT=6379

Step 3: Run pethost deploy

$ cd counter
$ pethost deploy
Name it [counter]:              it will live at https://counter.sam.pethost.app
✓ Packed 6 files, 1 KB   (took .env from this folder)
✓ Uploaded straight to your machine
✓ Built and started in 28 s
✓ web listens on 5000 → https://counter.sam.pethost.app
  It answers 200.

https://counter.sam.pethost.app

Wrote .pethost (commit it). Next:   pethost logs -f   ·   pethost open

It asks the project's name, the first word of its address, which never changes; Enter takes the folder's. The machine built web, pulled redis:alpine and waited until both ran. Commit .pethost, which names the project.

Step 4: Open the address

$ curl https://counter.sam.pethost.app/
Hello from Docker! I have been seen 3 time(s).

The count starts above 1 because your machine and pethost deploy asked the new address first, to see that it answers.

Deploy from the panel: an archive or a GitHub repository

Step 1: Click + New

New project offers GitHub repository, Upload an archive, Write compose.yaml and From a template, with the databases under them.

New project, its first step. The four ways to start a project, and the one-click databases under them.
The New project dialog of the Pethost panel: GitHub repository, Upload an archive, Write compose.yaml and From a template, then Postgres 18, MariaDB 11 and Valkey 9 under Database.

Step 2: Drop an archive, or pick a repository

An archive is a .zip, .tar or .tar.gz of the folder, and the panel says what will run: “Runs its compose.yaml.” A repository is one of your own GitHub account's, with its Branch and Directory in the repository; Install on more repositories lets Pethost's GitHub App read it. Then Next.

Step 3: Check the variables, then Create project

Environment variables is the project's .env: an archive's own fills it, and for a repository, which seldom holds one, you type its lines. Create project deploys it.

The project, deployed. counter's two services, redis healthy and web running, its address, and its requests of the last day.
The counter project's Overview tab in the Pethost panel: requests, errors, response time and uptime, the services redis and web with their memory, the source, and the address counter.sam.pethost.app.

Deploy it with your AI agent

Step 1: Install the Pethost plugin

Tell your agent: “Install the Pethost plugin from https://github.com/pethost-dev/plugin for yourself.” You approve it in your browser. The plugin's page has the command for Claude Code, Codex, Cursor and others.

Step 2: Ask for the deploy

Claude Code

You say: Deploy this Compose app and send me the link.

  • GetMachine sam.pethost.app, no project counter yet
  • CreateTransfer counter.tgz uploaded
  • CreateProject counter: succeeded

The agent answers: It's live at https://counter.sam.pethost.app. Your compose.yaml ran as written.

The agent sends the folder as it is, and fixes what a refusal names: how an agent deploys a project.

Which service gets the public address?

Pethost keeps ports: as you wrote it, and asks each published TCP port what it is:

  • A port that answers HTTP gets an HTTPS address and is not opened on the machine: "${APP_PORT}:5000", 8000:5000 here, became https://counter.sam.pethost.app, sent to port 5000 of web. Where several services answer HTTP, each gets <project>-<service>.sam.pethost.app.
  • Any other published port opens on the machine as written, to anyone. "6379:6379" under redis would put Redis on the internet: leave it out, or bind it to 127.0.0.1, which is never opened. pethost tunnel redis reaches it either way.
  • A service with no ports: is private: the project's services reach it at redis:6379.

To send a path to another service, say an api beside web, write routes under x-pethost. port is the port in the container, 5000, not 8000:

compose.yaml
x-pethost:
  routes:
    - {host: counter.sam.pethost.app, service: web, port: 5000}
    - {host: counter.sam.pethost.app, path: /api, service: api, port: 8000, strip_path: true}

The file's x-pethost counts at the first deploy; later ones keep the project's, so change routes on the Domains tab or with pethost domain add hits.sam.pethost.app. A domain you own is one DNS record: give an app a custom domain.

Where does the data live?

In named volumes. Whatever else a container writes is lost when it is made anew, by a deploy that changes its service or by pethost restart --pull. The quickstart's step 5 mounts a volume. That file, with step 3's healthcheck, ran as written:

compose.yaml, step 5: the volume's lines
  redis:
    image: redis:alpine
    volumes:
      - redis-data:/data

volumes:
  redis-data:

The deploy that added it started the count over, as Redis moved to the empty volume. Since then it goes on, in a new container too:

$ pethost restart --pull redis
counter (.pethost)
✓ redis runs in a new container, on the newest image of its tag, in 6 s.
$ curl https://counter.sam.pethost.app/
Hello from Pethost! I have been seen 4 time(s).

Every deploy and rollback keeps the volume, and nightly backups hold it, off the machine, for 14 days: pethost backup restore <id> --volume redis-data puts it back. A bind mount of a folder without :ro, ./data:/data, gets the project's volume data, not your folder's files.

Environment variables and secrets

The folder's .env goes with the first deploy only; after that the project keeps its own, and a deploy does not replace it. It fills each ${…} in compose.yaml, and a service gets a variable only where compose.yaml passes it:

$ pethost env
counter (.pethost)
APP_PORT     no service reads it
REDIS_HOST   web
REDIS_PORT   web
Their values:  pethost env --show

$ pethost env set SECRET_KEY
counter (.pethost)
SECRET_KEY: ••••••••
✓ /.env has SECRET_KEY now. Deployed in 1 s.

A bare name asks for the value without showing it. web reads SECRET_KEY once compose.yaml passes it, as - SECRET_KEY=${SECRET_KEY} under environment:, or env_file: .env for every variable. After pethost deploy:

$ pethost env
counter (.pethost)
APP_PORT     no service reads it
REDIS_HOST   web
REDIS_PORT   web
SECRET_KEY   web
Their values:  pethost env --show

pethost env push sends the folder's .env again, after naming what would go. A literal $ in compose.yaml is written $$. An email provider's key goes in the same way: send email from your app.

Deploy a new version, and roll back

Change the code and run the same command. The build's layers stay on the machine, so it took 3 seconds:

$ pethost deploy
counter (.pethost)
✓ Packed 7 files · uploaded · built and started in 3 s
  · kept the project's .env in place of the version's own: after the first deploy the project's is kept
  · kept the project's x-pethost
  It answers 200.
https://counter.sam.pethost.app
To send this folder's .env:  pethost env push

Your machine keeps the files of the three versions before the current one:

$ pethost rollback
counter (.pethost)
✓ Back on the version deployed today at 20:38, in 3 s.
  /.env, the routes and the volumes' data stay as they are now.
  This folder is as it was: the next pethost deploy puts its code online again.

pethost rollback --list shows the versions. To deploy every push instead, connect the repository once; a rollback then goes to a commit and stops following the branch until you run pethost github again:

pethost github sam/counter          # from now on, every push deploys itself

Run a database next to your app

A database service in compose.yaml, as redis here, runs as written, its data in a volume backed up with the project. Or make a one-click database, a project of its own: + New lists Postgres, MariaDB and Valkey, which Redis's clients work with. It comes with a data editor in the browser and backups of its own.

Linked at the app's create (CreateDatabase, then link_databases), the machine writes DATABASE_URL and its parts into the app's .env, so no password is copied. The app reaches it at the database's project id: Postgres in one click.

What compose.yaml features are not supported?

Few. The quickstart's last version, with include: ./infra.yaml and develop: watch, ran as written.

Compose features on Pethost
In compose.yamlOn PethostWrite instead
.:/code, the project mounted writableRefused.:/code:ro
privileged, cap_add, devices, host networking, the Docker socketRefused: they could reach the machineNothing
More than one replicaRefusedOne container a service
A volume's name, driver or externalRefusedThe volume's key alone
A volume with no name, - /dataRefused: no backup holds itdata:/data
include or extends from a URL, a git URL as build contextRefusedThe file in the folder
develop: watchAccepted, unused onlinepethost deploy
compose.override.yamlLeft outIts lines in compose.yaml

Where your compose.yaml is made for a laptop, keep it and write pethost.compose.yaml beside it: Pethost takes that file first. Every rule is in the API reference.

When a deploy fails

The file is refused. Each line with a cross names the place and what to write, and nothing changes on the machine:

$ pethost deploy
counter (.pethost)
  · kept the project's .env in place of the version's own: after the first deploy the project's is kept
  · kept the project's x-pethost
✗ services.web.volumes[0]: the bind mount at /code is of the project's whole directory and writable, but a deploy replaces the project's files: add :ro, and keep data in a folder of its own, e.g. ./data:/data
  Nothing was deployed. Change that in the folder, then run pethost deploy again.
  • A service exits or turns unhealthy. The deploy fails, its log ending with that service's last 20 lines: pethost logs --deploy. pethost why shows what is wrong.
  • The address answers 502. Nothing listens on the routed port, or only at 127.0.0.1, which the proxy cannot reach. That is why the quickstart's Dockerfile sets FLASK_RUN_HOST=0.0.0.0.
  • A port is taken. A published port that is not HTTP and that another project holds fails the deploy: change the number left of the colon.
  • An image declares a VOLUME nothing mounts. Mount a named volume there.

Questions

Can I deploy a docker-compose.yml file?

Yes. Pethost takes compose.yaml, compose.yml, docker-compose.yml or docker-compose.yaml at the folder's root, and pethost.compose.yaml before any of them. Override files are left out.

Do I need to change my compose file for Pethost?

Usually not: Docker's Compose quickstart ran unchanged. A file Pethost will not run is refused before anything starts, saying what to write instead.

How do I add a custom domain to a Compose app?

Run pethost domain add www.example.com in the project's folder. It prints one DNS record to make, and the certificate comes by itself once the name resolves: the custom domain guide.

How much does Docker Compose hosting cost on Pethost?

Starter is €9.99 a month for 2 vCPU, 3 GB of memory and 30 GB of SSD, for as many projects as fit; Grow is €17.99 for twice that. Nothing is metered. There is no free tier, and prices are without VAT: the plans.

The screens are deploys of Docker's Compose quickstart, read on 29 October 2026, on a test machine of ours. Other hosts that take a Compose file: managed Docker Compose hosting in 2026.

Run your apps on Pethost

Deploy apps, bots and databases from your agent, GitHub or the browser, as many as fit, at one flat price. Nothing metered, nothing billed on top.

Host all your projects for €9.99/mo