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 thedockergroup)
Installing the binary
From a release
Download deeplo from GitHub Releases and install it:
sudo install -m 755 deeplo /usr/local/bin/deeploBuild 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
| Path | Purpose |
|---|---|
/usr/local/bin/deeplo | deeplo binary (daemon + CLI) |
/etc/deeplo/config.yml | Managed config (hosts, repos, projects) |
/etc/deeplo/deeplo.env | Bootstrap env file (runtime settings) |
/etc/deeplo/keys/deploy_key | SSH private key |
/var/lib/deeplo/ | Data dir — git mirrors, state, run logs |
/var/lib/deeplo/known_hosts | SSH known_hosts (auto-created) |
/run/deeplo/deeplo.sock | Admin socket (internal; used by runtime commands) |
/etc/systemd/system/deeplo.service | Systemd 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/deeploDeploy 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_keyCopy 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 userEnv 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.envFor 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-1Validate it offline before starting the daemon:
deeplo check --config /etc/deeplo/config.ymlFor 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 deeploRuntimeDirectory=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 statusExpected deeplo health output when running:
Service: running
Enabled: yes
Socket: present
Daemon: reachable
Version: v0.1.0
Uptime: 1h23m45sFirewall 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/tcpGitHub webhook setup:
- Settings → Webhooks → Add webhook in your repo
- Payload URL:
https://your-host:8080/webhooks/github - Content type:
application/json - Secret: content of your
DEEPLO_GITHUB_WEBHOOK_SECRET_FILE - 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 versiondeeplo 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 healthIn-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 userDocker deployment
If you prefer running deeplo in a container, see Run with Docker.