A neat helper that manages the standby state of unix hosts with Wake-On-Lan (WOL) configured, with Web-GUI.
Note: LARGE parts of this project were LLM generated. None were blindly committed, but it is what it is.
played at 2x speed, using the WebUI installed as PWA
You can try a demo of the ShutHost WebUI (no backend, simulated data) via GitHub Pages:
This demo runs entirely in your browser and does not control any real hosts. It is useful for previewing the UI and features without installing anything. Note that the theme (light/dark) is selected based on your system preference.
- Manage standby state of Unix hosts with Wake-On-Lan (WOL) and lightweight agents
- Web-based GUI for easy management
- Light/Dark theme are selected based on system preference (with CSS media queries)
- installable as PWA
- this allows behavior similar to an native app on e.g. Android
- API for machine-to-machine control (e.g. backups)
- Should support extension (e.g. Home Assistant)
- Docker and simple binary deployment options (Docker has some strict requirements though)
- Convenience scripts for simple agent/client installation
- An attempt at extensive documentation
- πΏ Installation
- π· UI screenshots
- οΏ½π Requirements
- π Security
- ποΈ Architecture
- π API Documentation
β οΈ Known Issues- π Potential Features
Choose either the binary (recommended for reliability and WOL support) or the container (Linux only) installation.
Binary (recommended)
- Download the latest release from:
- Example (adjust filename for the asset you downloaded):
curl -L -o shuthost_coordinator "https://github.com/9SMTM6/shuthost/releases/download/latest/shuthost_coordinator-x86_64-unknown-linux-gnu" chmod +x shuthost_coordinator - Install as a system service (binary supports systemd/openrc/launchd)
- Install command (runs the chosen platform service installer, creates config with correct permissions and enables start-on-boot):
# Linux (recommended run with sudo) sudo ./shuthost install <optional user> # macOS (user is required on macOS) sudo ./shuthost install your-username
- Notes:
- On Linux the installer infers the target user from SUDO_USER if you run under sudo.
- The installer will create service units for systemd or openrc where appropriate and set config file ownership/permissions.
- Install command (runs the chosen platform service installer, creates config with correct permissions and enables start-on-boot):
Docker (Linux only)
- docker-compose example:
version: "3.8" services: shuthost: image: ghcr.io/9smtm6/shuthost/shuthost-coordinator:latest network_mode: "host" # required for WOL restart: unless-stopped volumes: - ./coordinator_config/:/config/:ro - ./data/:/data/ # persist DB and generated certs here, optional # no ports, since network_mode: host
- CLI example:
docker run --rm --network host \ -v ./coordinator_config.toml:/config/coordinator_config.toml:ro \ -v ./data/:/data/ \ ghcr.io/9smtm6/shuthost/shuthost-coordinator:latest
- Both with config file
# coordinator_config.toml
# ensure only you can read this file with `chmod 600 $(whoami) ./coordinator_config/coordinator_config.toml`
[server]
port = 8080 # change accordingly
bind = "127.0.0.1" # forward to this with your local reverse proxy.
[server.auth.token]
# token = "change-me" # uncomment and change to a secure token to avoid auto-generation
[db]
path = "/data/shuthost.db"
# Use this to enable TLS directly on the coordinator (either with provided certs or using the automatically generated self-signed certs)
# [server.tls]
# cert_path = "/data/cert.pem"
# key_path = "/data/key.pem"
# persist_self_signed = true
[hosts]
[clients]- Notes:
--network hostis Linux-only and will not work properly on Docker Desktop for Mac/Windows. Use the binary there or run on a Linux VM with bridged networking.
Agent / Client installation
- To install a host-agent (controls the hosts): open the web UI, open "Install Host Agent" and follow the instructions shown.
- To install a client (M2M, e.g., backup scripts): switch to the Clients tab, open "Install Client" and follow the instructions shown.
More screenshots can be found in the frontend/tests/visual-regression.spec.ts-snapshots and the frontend/tests/mobile-visual-regression.spec.ts-snapshots folders. These are generated or validated automatically as part of the test suite, and thus are guaranteed to be up-to-date (if the tests pass).
![]() |
![]() |
![]() |
![]() |
For the requirements for the agent, see Requirements to install the agent.
The coordinator must be run on a system that can reach the hosts you want to manage.
Assuming that the coordinator-host is on the same network as the hosts, with WOL broadcasts allowed, this requires additionally:
- π§ Running the coordinator as a binary on the coordinator-host, or
- π³ Running it in a docker container with the host network mode enabled
β οΈ Important: This does not work with the default network mode that docker uses on Windows and MacOS. It will also not work on WSL. On these Hosts, you will have to run the coordinator as a binary, or install a Linux VM with bridged networking to run docker.
β Windows is currently not supported, even with the binary and/or WSL. You need a VM or a dedicated Linux machine.
The coordinator binary exposes its server on 127.0.0.1 only by default - so on localhost, ipv4, without remote access. This is for security reasons.
To access the WebUI served by the binary from Docker containers (e.g. NGINX), use the address:
http://host.containers.internal:<port>
Container solutions other than Docker (e.g. Podman) might require additional configuration. On Podman, add the following to the container that wants to access the coordinator:
extra_hosts:
- "host.docker.internal:host-gateway"Alternatively, you can set the address the coordinator binds to in the configuration file.
β οΈ Warning: The WebUI is not secured by default, you should enable the built-in authentication or use a reverse proxy that provides authentication, and do the same with TLS.
ShutHost can also enforce simple auth on its own, either with a static token or with OIDC login. If you enable this, you don't need external auth.
In your shuthost_coordinator.toml add under [server]:
[server]
port = 8080
bind = "127.0.0.1"
# Choose one auth mode:
[server.auth.token]
# Token mode: provide a token or omit to auto-generate on startup (printed in logs, but that will be lost on restart)
# token = "your-secret-token"
# OIDC mode (authorization code flow with PKCE)
# [server.auth.oidc]
# issuer = "https://issuer.example.com/realms/foo"
# client_id = "shuthost"
# client_secret = "supersecret"
# # optional, defaults to ["openid","profile"]
# scopes = ["openid","profile"]
# External auth mode (reverse proxy or external authentication provider)
# [server.auth.external]
# exceptions_version = 1 # Version of exceptions acknowledged by operator
# Optional: base64-encoded cookie signing key (32 bytes). If omitted, a random key is generated
# cookie_secret = "base64-encoded-32-bytes=="Note that auth modes are mutually exclusive, and both require TLS on the browser end, so need either configured TLS or a reverse proxy that provides TLS.
If proxy unencrypted traffic with an external proxy, this will not be detected, and poses a security risk, as well as a potential source for issues. Such a setup is neither recommended nor supported.
For external auth, you need to add the following exceptions. The WebUI will show you convenience configs for some auth providers if you set exceptions_version=0.
Public endpoints (bypass):
/download/*,/manifest.json,/favicon.svg,/architecture*.svg/api/m2m/*(M2M API, e.g. for clients)
All other routes should be protected by your external auth.
If you want the coordinator to serve HTTPS directly, add a [server.tls] table. Paths are interpreted relative to the config file when not absolute. Example:
[server.tls]
# cert_path = "./tls_cert.pem" # path to certificate PEM (default: ./tls_cert.pem)
# key_path = "./tls_key.pem" # path to private key PEM (default: ./tls_key.pem)
# persist_self_signed = true # if true (default) generate and persist a self-signed cert when none providedBehavior:
- If both
cert_pathandkey_pathpoint to existing files, the coordinator will use them for TLS. - If the files they point to are absent and
persist_self_signedis true (the default), the coordinator will generate a self-signed cert/key and write them to the provided locations for reuse across restarts.
OIDC authentication in ShutHost has only been tested with kanidm. The following steps describe how to set up OIDC login using kanidm:
-
Create the OAuth2 application in kanidm:
kanidm system oauth2 create shuthost "Shuthost" https://shuthost.example.com kanidm system oauth2 add-redirect-url shuthost https://shuthost.example.com/oidc/callback kanidm group create shuthost_users kanidm group add-members shuthost_users <groups or users allowed to see UI> kanidm system oauth2 update-scope-map shuthost shuthost_users profile openid kanidm system oauth2 show-basic-secret shuthost
- Replace
https://shuthost.example.comwith your actual ShutHost URL. - Note the client secret output by the last command.
- Replace
-
Configure ShutHost to use OIDC: In your
coordinator_config.toml:[server.auth.oidc] issuer = "https://kanidm.example.com/oauth2/openid/shuthost" client_id = "shuthost" client_secret = "<the secret from above>"
- Adjust the
issuerURL to match your kanidm instance. - Use the client secret from the previous step.
- Adjust the
-
Restart ShutHost to apply the changes.
With this setup, users will be able to log in to the WebUI using their kanidm credentials. Only members of the
shuthost_usersgroup will have access.
- β Host agents are secured with HMAC signatures and timestamps against replay attacks
- β Only the coordinator that knows these (shared) secrets can use them
β οΈ Warning: All traffic between the coordinator and agents is unencrypted and only secured with HMAC signatures. This means that while status checks and commands are protected from tampering, anyone on the same LAN can observe the traffic and infer host statuses.
- β The client is secured in the same way as agents are
- β The coordinator only accepts requests from registered clients
To use the convenience scripts suggested by the WebUI, you will have to configure exceptions in the authorization of your reverse proxy, so that the requests from the host agents and clients are not blocked. These are detailed above.
The WebUI will show you the required exceptions, alongside convenience configs for:
- π Authelia
- π NGINX Proxy Manager
- π¦ Generic forward-auth in traefik
π See Architecture Documentation
π See API Documentation for details on:
- Coordinator M2M API: Machine-to-machine lease management and control
- Agent Protocol: Host management commands and status checking
This documentation is intended to help with third-party integrations, including custom scripts and systems like Home Assistant.
| Issue | Description | Impact | Solution |
|---|---|---|---|
| οΏ½π Missed Shutdown | If the host misses the initial shutdown, a "full cycle" is required to send it again (release lease, take lease) | Medium | [APP-SIDE] Regularly "syncing" states, either with explicit config on the host or coordinator-wide |
| πΎ State Loss | The coordinator loses state on restart only when no database is configured or persisted between runs | Low (fix available) | Configure the [db] section and persist the database file (e.g. keep the SQLite file or mount the volume in Docker) |
| πͺ Windows Support | Windows agent support currently not planned, due to large differences in the way services are implemented | N/A | N/A |
| π Docker Connectivity | Accessing the coordinator from Docker requires proper configuration | Medium | Ensure proper Docker network configuration |
| π Default Network Interface Selection | The agent installation chooses the default network interface to determine the IP, MAC, etc. for the config, which may not always be correct | Low | Manually override the network interface in the configuration |
| π§ glibc Version Errors | On certain distributions (e.g., Ubuntu 22.04), the coordinator binary may fail due to incompatible glibc versions | Low | Use the musl binary or the container for the coordinator. For the agent the install script will recommend the correct override to get the musl binary if the original binary fails |
| π Self-signed Certs & Install Scripts | The client and agent install scripts may fail if you use self-signed certs without proxying these elsewhere | Medium | proxy self-signed certs through a trusted endpoint or provide accepted certs from letsencrypt |
| πͺͺ OIDC Session Revalidation | OIDC login sometimes fails to revalidate the session and shows a generic OIDC error. Simply clicking "Login with SSO" again logs you in successfully. | Low | Currently undiagnosed due to lack of data. Workaround: click "Login with SSO" to log in. |
- π Custom Wakers: Support for alternative wake mechanisms beyond WOL, such as smart plugs or custom scripts (e.g., via API integrations). This would allow hosts without WOL support to be managed through external devices or services.
- π‘ BSD support might happen
β οΈ Requires using more advanced cross compilation- I have no ability to test these practically myself.
- ποΈ Uninstalls
- π Self-registration endpoint for host agents
- β Unclear how to deal with authorization:
- Server secret?
- β Unclear how to deal with authorization:




