A simple API and UI for executing and scheduling system commands or scripts. Great for webhooks and automating Linux server operations over HTTPS contained in a small binary.
- Use Cases
- Key Features
- Quick Start
- YAML Definitions Configuration
- API Endpoints
- Configurations
- Built-In Variables
- YAML Server Configurations
- Example
pal-actions.yml
- Homelab automation
- Simple job/CI server
- HTTP API for server management
- Sync small data in a simple secure Key/Value store
- Hide command output
- Cache last response / command output
- Create basic notifications inside pal
- Dynamic routing with easy YAML configurations
- Secure HTTP endpoints with auth header restriction
- File upload/download via a basic UI with Basic Auth
- Optional easy to use HTML UI (Works Offline/Air-Gap)
- Single binary (<20MB) with no external dependencies
- Control command execution: concurrent or sequential, background processes
- Secure key-value storage with BadgerDB (encrypted local filesystem database)
- Pass data to commands or scripts via env variables (Built-In Env Variables)
Prerequisites: Go 1.23 or higher
make
make certs
./pal -c ./pal.yml -d ./test/pal-actions.yml
make linux
make certs
make docker # Default configurations
Available Docker Run Env Variables:
# Default values
-e HTTP_LISTEN="127.0.0.1:8443"
-e HTTP_TIMEOUT_MIN="10"
-e HTTP_BODY_LIMIT="12M"
-e HTTP_CORS_ALLOW_ORIGINS='["*"]'
-e HTTP_AUTH_HEADER='X-Pal-Auth PaLLy!@#890-'
-e HTTP_UI_BASIC_AUTH='admin p@LLy5'
-e DB_ENCRYPT_KEY='8c755319-fd2a-4a89-b0d9-ae7b8d26'
Default Access: https://127.0.0.1:8443
(See Configurations to customize)
# Group name: e.g., /v1/pal/run/deploy
deploy:
- # Action name: e.g., /v1/pal/run/deploy/app
action: app
# Description of action
desc: Deploy app
# Auth header: e.g., curl -H'X-Pal-Auth: secret_string_here'
auth_header: X-Pal-Auth secret_string_here
# Show command output (default: false)
output: true
# Run in background (default: false)
background: false
# Run concurrently (default: false)
concurrent: true
# Set action to run multiple cron style schedules
crons:
- "*****"
# Set command timeout in seconds (default: 600 seconds/10 mins)
timeout: 600
# Set custom HTTP Response Headers
headers:
- header:
value:
# Validate input provided to run, valid options can be found here https://github.com/go-playground/validator?tab=readme-ov-file#baked-in-validations
input_validate: required
on_error:
# Send notification when an error occurs using built-in vars $PAL_GROUP $PAL_ACTION $PAL_INPUT $PAL_OUTPUT
notification: "deploy failed group=$PAL_GROUP action=$PAL_ACTION input=$PAL_INPUT output=$PAL_OUTPUT"
# Try cmd number of times
retries: 1
# Pause in seconds before running the next retry
retry_interval: 10
# Set list of string tags no format/convention required
tags:
- deploy
# Command or script (use $PAL_INPUT for variables)
cmd: echo "helloworld" && echo "$PAL_INPUT"
Example Request
curl -sk -H'X-Pal-Auth: secret_string_here' 'https://127.0.0.1:8443/v1/pal/run/deploy/app?input=helloworld2'
curl -sk -H'X-Pal-Auth: secret_string_here' -XPOST -d 'helloworld2' 'https://127.0.0.1:8443/v1/pal/run/deploy/app'
Run command using either GET (query param) or POST (post body). Access last cached output of command run.
Query Parameters:
input
: input to the running script/cmd also known as parameter or argumentlast_output
: return only the last ran output and do not trigger a run, basically a cache
GET /v1/pal/run/{{ group name }}/{{ action name }}?input={{ data }}
GET /v1/pal/run/{{ group name }}/{{ action name }}?last_output=true
POST {{ any data }} /v1/pal/run/{{ group name }}/{{ action name }}
group name
(Required): Key from your YAML configaction name
(Required): Action value associated with the groupdata
(Optional): Data (text, JSON) passed to your command/script as$PAL_INPUT
Get, put or dump all contents of the database. Meant to store small data <1028 characters in length (no limit, just recommendation).
PUT {{ any data }} /v1/pal/db/put?key={{ key_name }}
GET /v1/pal/db/get?key={{ key_name }}
GET /v1/pal/db/dump
DELETE /v1/pal/db/delete?key={{ key_name }}
any data
(Required): Any type of data to storekey name
(Required): Key to identify the stored datadump
returns all key value pairs from DB in a JSON object
cURL Key-Value Example
curl -vsk -H'X-Pal-Auth: PaLLy!@#890-' -XPUT -d 'pal' 'https://127.0.0.1:8443/v1/pal/db/put?key=name'
Basic healthcheck endpoint. Enable Prometheus configuration for metrics endpoint.
GET /v1/pal/health
- Returns "ok" response body
Upload and download files using a web request when enabled in the configuration.
GET [BASIC AUTH] /v1/pal/ui/files (Browser HTML View)
GET [BASIC AUTH] /v1/pal/ui/files/download/{{ filename }} (Download File)
POST [BASIC AUTH] /v1/pal/ui/files/upload (Multiform Upload)
filename
(Required): For downloading a specific file
cURL Upload Example
curl -vsk -F files='@{{ filename }}' -u 'admin:p@LLy5' 'https://127.0.0.1:8443/v1/pal/upload'
Create or get notifications and filter by group name.
GET /v1/pal/notifications?group={{ group_name }}
PUT {{ json_data }} /v1/pal/notifications
group_name
(Optional): Only show notifications for group provided
cURL Notification Example
curl -vks -H'X-Pal-Auth: PaLLy!@#890-' \
-d '{"notification":"THE QUICK BROWN FOX JUMPED OVER THE LAZY DOGS BACK 1234567890","group":"json"}' \
-H "content-type: application/json" -XPUT \
'https://127.0.0.1:8443/v1/pal/notifications'
Get configured cron actions or run cron action now.
GET /v1/pal/crons
GET /v1/pal/crons?group={{ group }}&action={{ action }}&run={{ run }}
group
(Required): group nameaction
(Required): action namerun
(Required): keyword "now" is only supported at this time. Runs action now.
Get action configuration including last_output and other run stats.
GET /v1/pal/action?group={{ group }}&action={{ action }}
group
(Required): group nameaction
(Required): action name
Usage: pal [options] <args>
-a, Set action definitions file path location, default is ./pal-actions.yml
-c, Set configuration file path location, default is ./pal.yml
Example: pal -a ./pal-actions.yml -c ./pal.yml
Every cmd run includes the below built-in env variables.
PAL_UPLOAD_DIR
- Full directory path to upload directory
PAL_GROUP
- Group name
PAL_ACTION
- Action Name
PAL_INPUT
- Input provided
PAL_REQUEST
- HTTP Request Context In JSON
{
"method": "",
"url": "",
"headers": { "": "" },
"query_params": { "": "" },
"body": ""
}
When OnError.Notification
is configured for the action, you can use available substitution variables in the notification message:
$PAL_GROUP
- Group name
$PAL_ACTION
- Action name
$PAL_INPUT
- Input provided
$PAL_OUTPUT
- Command error output
See latest example reference, here: https://github.com/marshyski/pal/blob/main/pal.yml
monitor:
- action: system
desc: Get primary system stats for monitoring
auth_header: X-Monitor-System q1w2e3r4t5
concurrent: false
background: false
output: true
cmd: |
echo '|===/ DOCKER STATS \===|'
command -v docker 1>/dev/null && sudo docker stats --no-stream; echo
echo '|===/ FREE MEMORY \===|'
free -g; echo
echo '|===/ DISK SPACE \===|'
df -hT; echo
echo '|===/ TOP CPU \===|'
ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head; echo
echo '|===/ TOP MEMORY \===|'
ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head; echo
echo '|===/ TOP OPEN FILES \===|'
lsof 2>/dev/null | cut -d" " -f1 | sort | uniq -c | sort -r -n | head; echo
echo '|===/ UPTIME AND LOAD \===|'
uptime
Example Request
curl -sk -H'X-Monitor-System: q1w2e3r4t5' 'https://127.0.0.1:8443/v1/pal/run/monitor/system'
For a more complete example, see: https://github.com/marshyski/pal/blob/main/test/pal-actions.yml