A lightweight, self-hosted configuration sync server. Clients authenticate with Ed25519 keypairs and retrieve project-scoped key/value config over a signed HTTP API. Backed by Turso (libSQL).
- Ed25519 request signing — every request is signed and timestamp-validated
- Admin / user role separation
- Project-scoped config with per-client read/write permissions
- Backed by Turso (remote) or any libSQL-compatible database (local file, in-memory)
- Single static binary, no runtime dependencies
curl -fsSL https://raw.githubusercontent.com/dickwu/CloudConfig/main/scripts/deploy.sh | sudo bashThe script will:
- Detect your architecture (x86_64 or aarch64)
- Download and verify the latest release binary
- Install it to
/usr/local/bin/cloudconfig - Create a config file at
/etc/cloudconfig/.env - Register and start a hardened systemd service
Update to latest release:
curl -fsSL https://raw.githubusercontent.com/dickwu/CloudConfig/main/scripts/deploy.sh | sudo bashForce reinstall the same version:
FORCE=1 curl -fsSL https://raw.githubusercontent.com/dickwu/CloudConfig/main/scripts/deploy.sh | sudo bashPin a specific version:
VERSION=v1.2.3 curl -fsSL https://raw.githubusercontent.com/dickwu/CloudConfig/main/scripts/deploy.sh | sudo bashbash <(curl -fsSL https://raw.githubusercontent.com/dickwu/CloudConfig/main/scripts/setup-mac.sh)Or manually:
brew tap dickwu/cloudconfig https://github.com/dickwu/CloudConfig
brew install cloudconfig
brew services start cloudconfigEdit config before starting:
$EDITOR "$(brew --prefix)/etc/cloudconfig/.env"
brew services restart cloudconfig# Build static frontend assets (required before cargo build)
cd frontend
bun install
bun run build
cd ..
cargo build --release --locked
./target/release/cloudconfig_sync_serverAll configuration is via environment variables (or a .env file in the working directory).
| Variable | Default | Description |
|---|---|---|
LISTEN_ADDR |
0.0.0.0:8080 |
TCP address to bind |
TURSO_URL |
:memory: |
libSQL connection string. Use libsql://… for Turso remote, ./cloudconfig.db for local file, or :memory: for in-process. |
TURSO_AUTH_TOKEN |
(empty) | Turso auth token. Not required for local databases. |
MAX_CLOCK_DRIFT_SECONDS |
300 |
Maximum allowed difference between request timestamp and server time. |
MAX_BODY_SIZE_BYTES |
1048576 |
Maximum request body size (1 MiB default). |
See .env.example for a ready-to-copy template.
On the very first startup, if no clients exist, the server automatically creates a bootstrap admin client and prints its credentials once:
Bootstrap admin created.
Client ID: <uuid>
Private key (store this safely, shown once):
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
Save the private key immediately. It will not be shown again.
All non-health endpoints require three headers:
| Header | Description |
|---|---|
X-Client-Id |
UUID of the authenticating client |
X-Timestamp |
Unix timestamp (seconds) |
X-Nonce |
Random string, used for replay prevention |
X-Signature |
Ed25519 signature of timestamp\nMETHOD\npath_and_query\nnonce\nsha256(body_bytes) |
GET /health → 200 "ok"
Requires an admin client.
| Method | Path | Description |
|---|---|---|
POST |
/admin/clients |
Create a new client |
GET |
/admin/clients |
List all clients |
DELETE |
/admin/clients/:id |
Delete a client |
POST |
/admin/projects |
Create a project |
GET |
/admin/projects |
List all projects |
POST |
/admin/projects/:id/configs |
Upsert a config key |
GET |
/admin/projects/:id/configs |
List configs for a project |
POST |
/admin/clients/:id/permissions |
Grant project permission |
DELETE |
/admin/clients/:id/permissions/:project_id |
Revoke permission |
Requires any authenticated client with appropriate permissions.
| Method | Path | Description |
|---|---|---|
GET |
/api/projects |
List projects the client has access to |
GET |
/api/projects/:id/configs |
Fetch all configs for a project |
GET |
/api/projects/:id/configs/:key |
Fetch a single config value |
Terminal 1 (frontend console):
cd frontend
bun install
bun run devTerminal 2 (API server):
cargo runGeneral Rust checks:
cargo test
# Lint
cargo clippy --all-targets --all-features
# Format
cargo fmtBefore cargo build or cargo run --release, run bun run build in frontend/ so frontend/out/ exists for Rust static embedding.
Releases are automated via GitHub Actions. To publish a new version:
git tag v1.2.3
git push origin v1.2.3CI will:
- Cross-compile for
x86_64-unknown-linux-gnu,aarch64-unknown-linux-gnu,x86_64-apple-darwin,aarch64-apple-darwin - Create a GitHub release with binaries and SHA256 checksums
- Automatically update
Formula/cloudconfig.rbwith the new URLs and hashes
MIT