---
title: Docker Compose
description: Run Human Plugin on a single host with Docker Compose, against your PostgreSQL database.
canonical: https://developer.unico.io/human-plugin/self-hosting/docker-compose
locale: en
generated_by: markdown-export
---

# Docker Compose

One Human Plugin container on one host, connected to your PostgreSQL database.

## Prerequisites

- Docker Engine 24 or later with Docker Compose v2.
- A PostgreSQL database dedicated to Human Plugin, reachable from the host. See [Prerequisites and access](/human-plugin/get-started/prerequisites).
- The registry credentials and the access key from Unico.

## 1. Log in to the registry

Once per host. Docker keeps the credential in `~/.docker/config.json`.

```bash
echo "<token>" | docker login pkg.unico.run -u <username> --password-stdin
```

## 2. Write the settings

Create a directory for Human Plugin and a `.env` file readable only by its owner:

```bash
mkdir -p /opt/human-plugin && cd /opt/human-plugin
```

```bash title=".env"
HUMAN_API_ACCESS_KEY=<your access key>
POSTGRES_ADDRESS_HOST=<database host>
POSTGRES_USER=human_plugin
POSTGRES_PASSWORD=<database password>
```

```bash
chmod 600 .env
```

Add `POSTGRES_ADDRESS_PORT`, `POSTGRES_DATABASE` or `POSTGRES_SSL_MODE` only if your database differs from the defaults in [Configuration](/human-plugin/self-hosting/configuration). Never commit the `.env` file.

## 3. Write `compose.yaml`

```yaml title="compose.yaml"
services:
  human-plugin:
    image: pkg.unico.run/human-plugin-api:latest
    pull_policy: always
    restart: unless-stopped
    stop_grace_period: 60s
    env_file: .env
    ports:
      - "127.0.0.1:8080:8080"
```

- **`ports`:** publish on `127.0.0.1` or on a private interface only, never on `0.0.0.0`. Human Plugin has no authentication of its own: see [Networking and security](/human-plugin/self-hosting/networking-and-security).
- **`stop_grace_period: 60s`:** Human Plugin waits up to 55 seconds for requests in flight when it stops. A shorter grace period can cut a create short.
- **`pull_policy: always`:** each `up` checks for the latest image, so you always run the most recent release.

## 4. Start

```bash
docker compose up -d
```

```bash
curl --fail http://127.0.0.1:8080/health/ready
```

Route traffic to Human Plugin only after `/health/ready` answers `200`. Then run the [Quickstart](/human-plugin/get-started/quickstart#3-create-a-process) create request against it.

## Logs and status

```bash
docker compose ps
```

```bash
docker compose logs -f human-plugin
```

A healthy start ends with the `human plugin listening` line. See [Health and monitoring](/human-plugin/self-hosting/health-and-monitoring#logs) for the full startup log. If the container restarts in a loop, the log states the reason: see [Troubleshooting](/human-plugin/additional-resources/troubleshooting).

## Update

```bash
docker compose pull && docker compose up -d
```

Compose replaces the container only when the image changed. See [Operations](/human-plugin/self-hosting/operations) for what to check after an update.

## Stop

```bash
docker compose down
```

Your data is in your PostgreSQL database, so stopping or removing the container loses nothing.