A remote control for your servers. The first Gotify plugin that talks back.
You're at a cafΓ©. Your phone buzzes β a service is down. You tap restart nginx. Five seconds later: β
nginx restarted.
No laptop. No SSH. No terminal. Just your phone and the Gotify app you already use.
23 commands. A visual control panel. Multi-machine support. One YAML config. Every other Gotify plugin forwards notifications somewhere else. This one lets you act on them.
Phone (Gotify app)
|
| "restart nginx"
v
Gotify Server <------------------------------+
| |
v |
gotify-commander plugin Web UI (Pico CSS)
| browser dashboard
+-- local: systemctl restart nginx (VPS services)
+-- SSH: launchctl unload/load (Mac services)
|
v
Response sent back
|
v
Phone notification
"Restart Nginx -- restarted on VPS (:80)"
Commands and responses flow through a single unified Gotify app β no separate channels to manage. Send a command, get the reply as the next notification.
- Download
gotify-commander-linux-amd64.sofrom Releases - Drop it in Gotify's plugin directory (usually
/opt/gotify/data/plugins/) - Restart Gotify:
sudo systemctl restart gotify - Open the Gotify WebUI -> Plugins -> gotify-commander -> Configure -> paste your YAML
- Enable the plugin
- Send
helpfrom the Gotify app on your phone
Access the web control panel at https://your-gotify-domain/plugin/gotify-commander/.
If you run Gotify in Docker, mount the plugin into the container:
# docker-compose.yml
services:
gotify:
image: gotify/server:2.6.1
volumes:
- ./gotify-data:/app/data
- ./gotify-commander-linux-amd64.so:/app/data/plugins/gotify-commander.so
ports:
- "2006:80"Download gotify-commander-linux-amd64.so from Releases and place it next to your docker-compose.yml.
Important: The .so file must be compiled with the exact same Go version as your Gotify image. The pre-built binary is compiled against Gotify 2.6.1.
| Command | Args | Description |
|---|---|---|
status |
[service] |
Status of all services, or a specific one |
restart |
<service> |
Restart a service (supports aliases) |
start |
<service> |
Start a service |
stop |
<service> |
Stop a service |
logs |
<service> |
Tail the last N lines of service logs |
services |
-- | List all managed services |
help |
-- | Show command reference + control panel link |
| Command | Args | Description |
|---|---|---|
free |
[vps/mac] |
Memory usage |
df |
[vps/mac] |
Disk usage (via duf) |
uptime |
[vps/mac] |
System uptime + load average |
top |
[vps/mac] |
Top processes by CPU/memory |
who |
[vps/mac] |
Currently logged-in users |
ping |
[vps/mac] |
Connectivity check |
ip |
[vps/mac] |
IP addresses |
connections |
[vps/mac] |
Socket statistics |
| Command | Args | Description |
|---|---|---|
traffic |
[service] |
Nginx traffic analysis via rhit (last 3 months) |
analytics |
-- | Web analytics summary via goaccess |
certs |
-- | SSL certificate expiry for all domains |
updates |
-- | Pending system updates (apt) |
| Command | Args | Description |
|---|---|---|
locate |
<lat> <lon> |
GPS reverse geocoding via OpenStreetMap |
| Command | Args | Description |
|---|---|---|
reboot |
<vps/mac> |
Reboot a machine (requires explicit target) |
shutdown |
<vps/mac> |
Shutdown a machine (requires explicit target) |
Universal aliases: mem/memory -> free -- disk/space -> df -- log -> logs -- up -> uptime
Typing just a service name (e.g. nginx) is treated as status nginx.
A browser dashboard built with Pico CSS lives at https://your-domain/plugin/gotify-commander/.
- Live service status grid β all services, grouped by category, color-coded
- One-click restart / start / stop for any service
- Command history with timestamps and results
- System metrics (memory, disk, uptime) at a glance
- Dynamic favicons fetched from service domains
- Dynamic categories from your YAML config β no hardcoding
Access is secured through your existing Gotify login. No extra credentials.
Configure via Gotify WebUI β no config files to edit manually. See config.example.yaml for the full structure.
gotify:
server_url: "http://localhost:2006"
base_url: "https://gotify.example.com" # public URL for web UI links
client_token: "your-client-token" # from Gotify -> Clients
command_app_id: 1 # ID of the unified command/response app
response_app_token: "your-token" # token for the same app
defaults:
timeout: 30s
log_lines: 30
categories:
web:
label: "Web"
type: web
media:
label: "Media"
type: media
monitoring:
label: "Monitoring"
type: monitoring
data:
label: "Data"
type: data
automation:
label: "Automation"
type: automation
system:
label: "System"
type: system
services:
nginx:
description: "Web Server"
category: web
domain: "example.com" # used by 'cert' and 'dns' commands
machine: vps
port: 80
aliases: [ng, web]
systemd: nginx
homeserver:
description: "Home Server"
category: media
machine: mac
port: 8080
aliases: [home]
launchd: com.myapp.serviceRequired fields per machine type:
machine: vpsβ requiressystemd(unit name forsystemctl)machine: macβ requireslaunchd(label forlaunchctl) + SSH target configured
- client_token: Go to Gotify WebUI β Clients β Create a new client β copy the token
- command_app_id: The plugin creates its own app (ID shown in Plugins page). Set this to that app's ID for unified commands + responses
- response_app_token: Not used in unified mode β can be any valid app token
Services are grouped into categories defined in your YAML config. The 6 default categories:
| Category | Typical services |
|---|---|
web |
nginx, caddy, traefik |
media |
Jellyfin, TubeArchivist, Plex |
monitoring |
Grafana, Prometheus, Uptime Kuma |
data |
PostgreSQL, Redis, Meilisearch |
automation |
n8n, Home Assistant, cron jobs |
system |
SSH daemon, Fail2ban, Gotify itself |
Categories drive both the services command output and the web UI grouping. Add your own by extending the categories section.
gotify-commander supports two machine types out of the box:
VPS β commands run locally on the same server where Gotify is installed. Uses systemctl for service management.
Mac β commands are sent over SSH to a remote Mac Mini or MacBook. Uses launchctl for service management.
ssh_targets:
mac: # must be named "mac" to auto-wire
host: "100.x.x.x" # Tailscale IP recommended
port: 22
user: "admin"
key_file: "/home/admin/.ssh/id_rsa"Once configured, free mac, df mac, uptime mac, and services with machine: mac all route through SSH automatically.
gotify-commander executes real system commands on your server. Treat it with the same caution as SSH access.
- Anyone who can send a message to the configured Gotify app can execute commands. This includes Gotify users with access to that application, or anyone who obtains a valid app token.
- The web control panel serves its HTML page without authentication. The API endpoints (
/execute,/health,/config) are protected byweb_passwordif configured β but it is not set by default. Without it, anyone who can reach your Gotify server can execute commands through the web UI.
- Only the 23 registered commands can run. No arbitrary command execution.
- Service names are validated against
^[a-zA-Z0-9][a-zA-Z0-9._-]*$and must match your configured whitelist. - Most commands use
exec.Command(no shell). However, four commands usebash -c:certs,traffic,analytics, andlocate. User input reaching these shells is validated (alphanumeric for service names, numeric-only for GPS coordinates), but a shell is invoked. - The plugin runs with the same permissions as the Gotify process.
- Command output (process lists, memory usage, IP addresses, open ports, SSL cert details) flows back as Gotify notifications visible to anyone who can read that app's messages.
- The
locatecommand sends GPS coordinates to the OpenStreetMap Nominatim API for reverse geocoding β your coordinates are sent to a third-party service. - The web UI
/configendpoint exposes your service list, ports, and machine names.
- Run Gotify behind a VPN (Tailscale, WireGuard). Do not expose Gotify to the public internet. This is the single most important security measure.
- Set a strong Gotify admin password.
- Set
web_passwordin your config to protect the web control panel. - Use HTTPS for all Gotify traffic.
- Restrict Gotify app tokens. Only create tokens for devices you control.
| Layer | Status |
|---|---|
| Command whitelist (23 commands) | β Enforced |
| Input sanitization (regex) | β Enforced |
| Service name whitelist | β Enforced |
| Execution timeouts (30s default) | β Enforced |
| Gotify authentication | β Enforced (Gotify's own auth) |
| Web UI API authentication | web_password, off by default) |
| Rate limiting | β Not implemented |
| Per-command authorization | β Not implemented |
| SSH host key verification | β Disabled (InsecureIgnoreHostKey) |
| Feature | gotify-commander | Telegram Bots | Uptime Kuma |
|---|---|---|---|
| Self-hosted | Yes | No | Yes |
| Bidirectional | Yes | Yes | No |
| Runs inside Gotify | Yes | No | No |
| No third-party services | Yes | No | Yes |
| Service management | Yes | varies | No |
| Multi-machine (SSH) | Yes | varies | No |
| Web control panel | Yes | No | Yes |
| Traffic & analytics | Yes | No | No |
| GPS locate | Yes | No | No |
| Tailscale security | Yes | No | No |
| Phone app already installed | Yes | Yes | No |
Some commands rely on utilities installed on the server. The plugin works without them, but those specific commands will fail.
| Command | Requires | Install | Notes |
|---|---|---|---|
df |
duf | apt install duf |
Falls back to standard df if not found |
traffic |
rhit | Download from releases | Nginx log analyzer |
analytics |
goaccess | apt install goaccess |
Web analytics from nginx logs |
analytics |
python3 |
Pre-installed on most distros | Parses goaccess CSV output |
locate |
python3 + curl |
Pre-installed on most distros | Reverse geocoding via Nominatim |
certs |
openssl |
Pre-installed on most distros | Reads Let's Encrypt certificates |
ports |
ss |
Part of iproute2 |
Socket statistics |
top |
ps |
Part of procps |
Process listing |
All other commands use standard Linux utilities (systemctl, free, uptime, who, hostname, journalctl).
The plugin must be built on Linux with CGO_ENABLED=1 (Go plugins require cgo).
git clone https://github.com/drolosoft/gotify-commander
cd gotify-commander
go build -buildmode=plugin -o gotify-commander.so .
sudo cp gotify-commander.so /opt/gotify/data/plugins/
sudo systemctl restart gotifyUsing the Makefile:
make test # run unit tests
make lint # go vet
make deploy # SSH -> build on VPS -> install -> restart Gotify
make deploy-dev # fast deploy, skip testsThe deploy target connects to your VPS via Tailscale, pulls the latest commit, builds in place, copies the .so, and restarts Gotify in one step.
Contributions are welcome β bug fixes, new commands, feature ideas. Open an issue or submit a PR.
If gotify-commander made your server management easier, consider giving it a star on GitHub β it helps others discover the project.
MIT License β free to use, modify, and distribute.
Drolosoft -- Tools we wish existed





