Deployment Guide
June 24, 2026 · View on GitHub
This guide covers building, deploying, and running HookRun in production environments.
0. One-Liner Install (Recommended)
No Go, no Docker — just one command:
curl -fsSL https://bluvenr.github.io/hookrun/install.sh | bash
What it does:
- Auto-detects your OS (Linux/macOS) and architecture (amd64/arm64)
- Downloads the latest pre-built binary from GitHub Releases
- Installs to
/usr/local/bin/hookrun - Runs
hookrun initto generateconfig.yamlandhooks/example.yaml
Custom Options
Use environment variables to customize:
# Install a specific version
curl -fsSL https://bluvenr.github.io/hookrun/install.sh | HOOKRUN_VERSION=1.1.3 bash
# Custom install directory
curl -fsSL https://bluvenr.github.io/hookrun/install.sh | HOOKRUN_INSTALL_DIR=$HOME/bin bash
# Use GitHub webhook template
curl -fsSL https://bluvenr.github.io/hookrun/install.sh | HOOKRUN_TEMPLATE=github bash
# Skip config init (binary only)
curl -fsSL https://bluvenr.github.io/hookrun/install.sh | HOOKRUN_INIT_DIR=skip bash
| Variable | Default | Description |
|---|---|---|
HOOKRUN_VERSION | latest | Pin a specific version (e.g. 1.1.3) |
HOOKRUN_INSTALL_DIR | /usr/local/bin | Binary install path |
HOOKRUN_INIT_DIR | . (current dir) | Directory for config init. skip to skip |
HOOKRUN_TEMPLATE | generic | Init template: generic, github, gitlab |
After Install
# Validate configuration
hookrun validate
# Start server
hookrun start
# Check status
hookrun status
1. Build from Source
Prerequisites
- Go 1.23 or later
- Git
Build
git clone https://github.com/bluvenr/hookrun.git
cd hookrun
go build -o hookrun ./cmd/hookrun/
Build with Version Info
Use -ldflags to inject version and build time:
go build -ldflags "-X github.com/bluvenr/hookrun/internal/version.Version=1.1.3 -X 'github.com/bluvenr/hookrun/internal/version.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)'" \
-o hookrun ./cmd/hookrun/
Cross-Compilation
Build for different platforms:
# Linux amd64
GOOS=linux GOARCH=amd64 go build -o hookrun-linux-amd64 ./cmd/hookrun/
# Linux arm64 (e.g. Raspberry Pi, AWS Graviton)
GOOS=linux GOARCH=arm64 go build -o hookrun-linux-arm64 ./cmd/hookrun/
# macOS amd64 (Intel)
GOOS=darwin GOARCH=amd64 go build -o hookrun-darwin-amd64 ./cmd/hookrun/
# macOS arm64 (Apple Silicon)
GOOS=darwin GOARCH=arm64 go build -o hookrun-darwin-arm64 ./cmd/hookrun/
# Windows amd64
GOOS=windows GOARCH=amd64 go build -o hookrun-windows-amd64.exe ./cmd/hookrun/
2. Directory Structure
Recommended production layout:
/opt/hookrun/
├── hookrun # Binary
├── config.yaml # Global config
├── hooks/ # Rule YAML files
│ ├── app-a.yaml
│ └── app-b.yaml
├── scripts/ # Custom scripts referenced by rules
│ └── deploy.sh
└── logs/ # Log output directory
└── hookrun-2026-06-11.log
Runtime data (PID file, status, signals) is stored in ~/.hookrun/:
~/.hookrun/
├── hookrun.pid # Process PID
├── hookrun.status # JSON status file
├── hookrun.reload # Reload signal file (Windows)
└── hookrun.stop # Stop signal file (Windows)
3. Linux Deployment
Option A: Direct Execution (Simple)
# Copy binary and config
cp hookrun /usr/local/bin/
mkdir -p /etc/hookrun/hooks
cp config.yaml /etc/hookrun/
# Run
cd /etc/hookrun
hookrun start
Option B: systemd Service (Recommended)
Create /etc/systemd/system/hookrun.service:
[Unit]
Description=HookRun - Webhook Action Engine
After=network.target
[Service]
Type=simple
User=hookrun
Group=hookrun
WorkingDirectory=/etc/hookrun
ExecStart=/usr/local/bin/hookrun start -f -c /etc/hookrun/config.yaml
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/etc/hookrun/logs
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Setup:
# Create user
sudo useradd -r -s /sbin/nologin hookrun
# Create directories
sudo mkdir -p /etc/hookrun/hooks /etc/hookrun/scripts /etc/hookrun/logs
sudo chown -R hookrun:hookrun /etc/hookrun
# Copy files
sudo cp hookrun /usr/local/bin/
sudo cp config.yaml /etc/hookrun/
sudo cp hooks/*.yaml /etc/hookrun/hooks/
# Set script permissions
sudo chmod +x /etc/hookrun/scripts/*.sh
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable hookrun
sudo systemctl start hookrun
# Check status
sudo systemctl status hookrun
Note: When using systemd, always use start -f (foreground) so systemd manages the process lifecycle directly.
Systemd Management Commands
# Stop
sudo systemctl stop hookrun
# Restart
sudo systemctl restart hookrun
# View logs
sudo journalctl -u hookrun -f
# Reload config (hot-reload)
hookrun reload -c /etc/hookrun/config.yaml
4. Docker Deployment
Option A: Pull Pre-built Image (Recommended)
docker pull ghcr.io/bluvenr/hookrun:latest
docker run -d \
--name hookrun \
-p 9000:9000 \
-v ./config.yaml:/app/config.yaml \
-v ./hooks:/app/hooks \
-v ./logs:/app/logs \
--restart unless-stopped \
ghcr.io/bluvenr/hookrun:latest
Available tags:
| Tag | Description |
|---|---|
latest | Latest stable release |
1.1.3 | Specific version |
1.1 | Latest patch in minor version |
Option B: Build from Source
FROM golang:1.23-alpine AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -trimpath -o hookrun ./cmd/hookrun/
FROM alpine:3.20
RUN apk --no-cache add ca-certificates tzdata
WORKDIR /app
COPY --from=builder /build/hookrun /usr/local/bin/hookrun
COPY config.yaml /app/
COPY hooks/ /app/hooks/
EXPOSE 9000
ENTRYPOINT ["hookrun", "start", "-f", "-c", "/app/config.yaml"]
# Build image
docker build -t hookrun:latest .
# Run
docker run -d \
--name hookrun \
-p 9000:9000 \
-v ./hooks:/app/hooks \
-v ./logs:/app/logs \
--restart unless-stopped \
hookrun:latest
Docker Compose
Using GHCR image (recommended):
version: "3.8"
services:
hookrun:
image: ghcr.io/bluvenr/hookrun:latest
container_name: hookrun
ports:
- "9000:9000"
volumes:
- ./config.yaml:/app/config.yaml
- ./hooks:/app/hooks
- ./logs:/app/logs
- ./scripts:/app/scripts
restart: unless-stopped
Or building from source:
version: "3.8"
services:
hookrun:
build: .
container_name: hookrun
ports:
- "9000:9000"
volumes:
- ./hooks:/app/hooks
- ./logs:/app/logs
- ./scripts:/app/scripts
restart: unless-stopped
Run:
docker compose up -d
5. Windows Deployment
Manual Setup
# Create directory
New-Item -ItemType Directory -Force -Path C:\hookrun\hooks
# Copy files
Copy-Item hookrun.exe C:\hookrun\
Copy-Item config.yaml C:\hookrun\
Copy-Item hooks\*.yaml C:\hookrun\hooks\
# Run
cd C:\hookrun
.\hookrun.exe start
Run as Windows Service
Use NSSM (Non-Sucking Service Manager):
nssm install HookRun C:\hookrun\hookrun.exe
nssm set HookRun AppParameters "start -f -c C:\hookrun\config.yaml"
nssm set HookRun AppDirectory C:\hookrun
nssm start HookRun
Windows-Specific Notes
- Process control: Uses signal file IPC (polled every 2 seconds) instead of Unix signals
- PID detection: Uses
tasklistcommand to check if process is running - Shell: Commands execute via
cmd /c
6. Reverse Proxy
Nginx
location /webhook/ {
proxy_pass http://127.0.0.1:9000/webhook/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Increase timeout for long-running actions
proxy_read_timeout 300s;
}
Caddy
webhook.example.com {
reverse_proxy localhost:9000
}
7. Security Recommendations
- Use authentication: Always set
auth.tokenin rule configs - IP whitelist: Restrict to known webhook source IPs where possible
- HTTPS: Use a reverse proxy with TLS termination
- Firewall: Only expose port 443 (HTTPS); keep port 9000 internal
- Least privilege: Run HookRun as a non-root user with minimal filesystem permissions
- Script permissions: Ensure scripts in
scripts/have appropriate execute permissions - Config validation: Always run
hookrun validateafter editing configs
8. Monitoring
Health Check Endpoint
curl http://localhost:9000/health
Response:
{"status": "ok", "uptime": "2h30m15s", "rules": 3, "version": "x.y.z"}
When relay is configured, the response includes a relay field:
{"status": "ok", "uptime": "2h30m15s", "rules": 3, "version": "x.y.z", "relay": {"role": "upstream", "upstream_targets": 2, "downstream_connected": true}}
Relay Status API
Use GET /api/relay/status (no auth required) to get detailed relay information:
# Check relay role and connectivity
curl http://localhost:9000/api/relay/status
# Check registered downstream targets
curl http://localhost:9000/api/relay/status | jq '.upstream.targets_count'
Or use the CLI:
# Show relay status
hookrun relay status
# List registered targets (token auto-read from config)
hookrun relay targets
# Override token if needed
hookrun relay targets --token your-registry-token
Log Monitoring
# Tail logs
tail -f logs/hookrun-$(date +%Y-%m-%d).log
# Count requests today
grep -c "Webhook request" logs/hookrun-$(date +%Y-%m-%d).log
# Check for errors
grep "ERROR" logs/hookrun-$(date +%Y-%m-%d).log
Integration with Monitoring Tools
Use the /health endpoint with:
- Prometheus: via
blackbox_exporterHTTP probe - Uptime Kuma: HTTP(s) monitor on
/health - Nagios/Zabbix: Custom check script hitting
/health