deeplo
Guides

Manual installation

Install deeplo and set up the systemd service manually without the installer script.

The installer script handles all of this automatically. Use this page when you need to understand each step, integrate with your own provisioning, or install on a system where running the script is not appropriate.

For Docker Compose deployment, see Run with Docker.


Prerequisites

Host where deeplo runs:

  • Linux with systemd
  • Git on PATH
  • An SSH private key with access to your deploy targets

Deploy targets (remote hosts):

  • SSH access for a deploy user
  • Docker with the Compose plugin (docker compose)
  • The deploy user able to run docker compose (typically via the docker group)

Installing the binary

From a release

Download deeplo from GitHub Releases and install it:

sudo install -m 755 deeplo /usr/local/bin/deeplo

Build from source

git clone https://github.com/jancernik/deeplo.git
cd deeplo
make build
sudo cp bin/deeplo /usr/local/bin/

Requires Go 1.25+, Make, Git.


Standard paths

PathPurpose
/usr/local/bin/deeplodeeplo binary (daemon + CLI)
/etc/deeplo/config.ymlManaged config (hosts, repos, projects)
/etc/deeplo/deeplo.envBootstrap env file (runtime settings)
/etc/deeplo/keys/deploy_keySSH private key
/var/lib/deeplo/Data dir — git mirrors, state, run logs
/var/lib/deeplo/known_hostsSSH known_hosts (auto-created)
/run/deeplo/deeplo.sockAdmin socket (internal; used by runtime commands)
/etc/systemd/system/deeplo.serviceSystemd unit

User and directory setup

# Create group first, then user bound to it
sudo groupadd --system deeplo
sudo useradd --system --no-create-home --shell /sbin/nologin --gid deeplo deeplo

# /etc/deeplo — world-traversable so normal users can run `deeplo check`
# Config and env contain no secrets; restricting them breaks the CLI for non-root users
sudo mkdir -p /etc/deeplo/keys
sudo chown root:root /etc/deeplo
sudo chmod 755 /etc/deeplo

# keys dir — restricted to root and the service group (private key lives here)
sudo chown root:deeplo /etc/deeplo/keys
sudo chmod 750 /etc/deeplo/keys

# Data directory — daemon owns fully (state, git mirrors, run logs)
sudo mkdir -p /var/lib/deeplo
sudo chown deeplo:deeplo /var/lib/deeplo
sudo chmod 750 /var/lib/deeplo

Deploy key

deeplo uses one SSH key for all connections: deploying to target hosts and fetching git repos.

sudo ssh-keygen -t ed25519 -f /etc/deeplo/keys/deploy_key -N ""
# root owns, service group can read — daemon can use the key, but cannot overwrite it
sudo chown root:deeplo /etc/deeplo/keys/deploy_key
sudo chmod 640 /etc/deeplo/keys/deploy_key

Copy the public key to each target host's deploy user:

sudo cat /etc/deeplo/keys/deploy_key.pub
# Append to ~/.ssh/authorized_keys on each target, logged in as the deploy user

Env file

Create /etc/deeplo/deeplo.env with your bootstrap settings:

sudo tee /etc/deeplo/deeplo.env > /dev/null <<'EOF'
DEEPLO_DATA_DIR=/var/lib/deeplo
DEEPLO_SSH_KEY_FILE=/etc/deeplo/keys/deploy_key
DEEPLO_SSH_USER=deploy

# Optional: webhook HMAC secret (omit if using poll mode only)
# DEEPLO_GITHUB_WEBHOOK_SECRET_FILE=/etc/deeplo/keys/github_webhook_secret

# Optional: GitHub deployment reporting
# DEEPLO_GITHUB_TOKEN_FILE=/etc/deeplo/keys/github_token

# Optional: serve run logs on a second port
# DEEPLO_LOGS_PORT=8081
# DEEPLO_LOGS_PUBLIC_URL=https://logs.example.com
EOF

sudo chown root:root /etc/deeplo/deeplo.env
sudo chmod 644 /etc/deeplo/deeplo.env

For all available variables, see Bootstrap config.


Managed config file

Create /etc/deeplo/config.yml. This file describes your deployment topology — hosts, repos, and projects. It contains no secrets.

version: 1

hosts:
  - name: web-1
    address: 10.0.0.10
    remote_base_dir: /srv/apps

repos:
  - name: myapp
    url: git@github.com:yourorg/myapp.git
    branch: main
    trigger_mode: hybrid
    poll_interval: 5m

projects:
  - name: myapp
    repo: myapp
    repo_subdir: deploy
    targets:
      - web-1

Validate it offline before starting the daemon:

deeplo check --config /etc/deeplo/config.yml

For the full YAML reference, see Configuration.


Systemd service

sudo tee /etc/systemd/system/deeplo.service > /dev/null <<'EOF'
[Unit]
Description=deeplo deployment daemon
Documentation=https://deeplo.dev/docs
After=network.target

[Service]
Type=simple
User=deeplo
Group=deeplo
EnvironmentFile=/etc/deeplo/deeplo.env
ExecStart=/usr/local/bin/deeplo daemon
Restart=on-failure
RestartSec=5s
RuntimeDirectory=deeplo
RuntimeDirectoryMode=0750

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now deeplo

RuntimeDirectory=deeplo tells systemd to create /run/deeplo/ before start and remove it on stop. The admin socket lives there by default.


Verification

# Check service status
sudo systemctl status deeplo

# Watch live logs
journalctl -fu deeplo

# Ping the daemon
deeplo health

# View deployment state
deeplo status

Expected deeplo health output when running:

Service:  running
Enabled:  yes
Socket:   present
Daemon:   reachable
Version:  v0.1.0
Uptime:   1h23m45s

Firewall and webhook setup

If you're using trigger_mode: webhook or trigger_mode: hybrid, port 8080 (or DEEPLO_WEBHOOK_PORT) must be reachable from GitHub.

# Allow inbound on webhook port (example for ufw)
sudo ufw allow 8080/tcp

GitHub webhook setup:

  1. Settings → Webhooks → Add webhook in your repo
  2. Payload URL: https://your-host:8080/webhooks/github
  3. Content type: application/json
  4. Secret: content of your DEEPLO_GITHUB_WEBHOOK_SECRET_FILE
  5. Events: Just the push event

If deeplo is not publicly reachable, use trigger_mode: poll instead.


Upgrading

The easiest way to upgrade is with the built-in update command:

deeplo update              # install latest release
deeplo update --version v0.2.1  # install a specific version

deeplo update downloads the new binary, restarts the daemon if it was running, and handles migration from legacy installs automatically.

To upgrade manually:

# Install new binary
sudo install -m 755 deeplo-new /usr/local/bin/deeplo

# Restart the daemon
deeplo service restart

# Verify
deeplo health

In-flight deploys are given 30 seconds to finish before the daemon stops.


Removing

deeplo remove           # remove binary and service; keep config and data
deeplo remove --purge   # also remove /etc/deeplo, /var/lib/deeplo, and the system user

Docker deployment

If you prefer running deeplo in a container, see Run with Docker.

On this page