Skip to Content
Server Setup

Server Setup

This guide covers installing and configuring the Creddy server.

Installation

Install the binary to /usr/local/bin:

curl -fsSL https://get.creddy.dev/install.sh | sudo sh -s -- --to /usr/local/bin

Install as a Daemon

Set up Creddy as a systemd service:

sudo creddy install --listen 0.0.0.0:8400

This automatically:

  • Copies the binary to /usr/local/bin/creddy (if needed)
  • Creates /var/lib/creddy for data storage
  • Creates /usr/local/lib/creddy/plugins for system plugins
  • Writes a hardened systemd unit file
  • Enables and starts the service

Options:

FlagDefaultDescription
--listen0.0.0.0:8400Address and port to listen on
--data-dir/var/lib/creddyData directory
--agent-inactivity-days0Auto-unenroll inactive agents (0 = disabled)

Managing the Service

systemctl status creddy # Check status journalctl -u creddy -f # View logs sudo systemctl restart creddy # Restart sudo creddy uninstall # Remove service

Diagnostics

Check your installation:

creddy which

Output:

Binary: Path: /usr/local/bin/creddy Checksum: a1b2c3d4... Config: → ✓ ~/.config/creddy/config.yaml ✗ /etc/creddy/config.yaml Plugins: Search order: 1. ✓ ~/.local/share/creddy/plugins (user) 2. ✓ /usr/local/lib/creddy/plugins (system) Service: Unit: /etc/systemd/system/creddy.service ExecStart: /usr/local/bin/creddy server --listen 0.0.0.0:8400 ... Status: active

Check version and updates:

creddy version creddy version --json # Machine-readable output

Configuration

Data Directory

The server stores data in /var/lib/creddy (or --data-dir):

/var/lib/creddy/ ├── creddy.db # SQLite database └── keys/ └── signing.key # Ed25519 signing key

Plugin Directory

System plugins are stored in /usr/local/lib/creddy/plugins.

User plugins (from creddy plugin install) go to ~/.local/share/creddy/plugins.

The server searches both directories, so you can install plugins either way.


Running Without systemd

Foreground (Development)

creddy server --listen 127.0.0.1:8400

Manual Systemd Setup

If you prefer to create the unit file yourself:

[Unit] Description=Creddy credential server After=network.target [Service] Type=simple ExecStart=/usr/local/bin/creddy server --listen 0.0.0.0:8400 --db /var/lib/creddy/creddy.db Restart=on-failure RestartSec=5 NoNewPrivileges=true ProtectSystem=strict ProtectHome=read-only ReadWritePaths=/var/lib/creddy [Install] WantedBy=multi-user.target
sudo systemctl daemon-reload sudo systemctl enable creddy sudo systemctl start creddy

Health Check

curl http://localhost:8400/health

Returns:

{ "status": "healthy", "version": "v0.0.9" }

TLS & OIDC Setup

OIDC requires HTTPS. Choose the approach that fits your setup:

Tailscale Funnel (Easiest)

If you’re on Tailscale, Funnel gives you instant public HTTPS:

# Expose Creddy publicly with TLS tailscale funnel 8400 # Start with OIDC creddy server --oidc-issuer https://mybox.tail1234.ts.net

Your issuer URL is your Tailscale machine name + .ts.net.

Caddy (Auto-TLS)

Caddy handles Let’s Encrypt automatically:

# Caddyfile creddy.example.com { reverse_proxy localhost:8400 }
# Start Caddy caddy run # Start Creddy creddy server --oidc-issuer https://creddy.example.com

nginx + certbot

# Get cert sudo certbot certonly --nginx -d creddy.example.com # nginx.conf server { listen 443 ssl; server_name creddy.example.com; ssl_certificate /etc/letsencrypt/live/creddy.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/creddy.example.com/privkey.pem; location / { proxy_pass http://127.0.0.1:8400; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

Cloud Load Balancer

AWS ALB, GCP LB, and Cloudflare all provide managed TLS:

  1. Point your LB to Creddy’s port
  2. Attach a managed certificate
  3. Use the LB’s hostname as your issuer
creddy server --oidc-issuer https://creddy.example.com

Internal Only (No Federation)

If you don’t need AWS/GCP federation and all agents are on your network:

# Tailscale-only (no public exposure) creddy server --oidc-issuer https://creddy.tail1234.ts.net # Agents on tailnet can verify tokens # External services (AWS) cannot

Note: For AWS/GCP OIDC federation, your issuer URL must be publicly reachable so they can fetch /.well-known/openid-configuration and /.well-known/jwks.json.


Remote Agent Provisioning

For automated workflows, set up a provisioner agent that can create other agents remotely.

1. Create the Provisioner (on server)

# SSH into your Creddy server creddy agent create provisioner --can "admin:agents:*"

Output:

{ "name": "provisioner", "token": "ckr_abc123...", "oidc": { "client_id": "agent_f8e7d6c5b4a3", "client_secret": "cks_xyz789..." } }

Save the OIDC credentials securely (e.g., in your secrets manager).

2. Use from Your Automation

Copy the env vars from the CLI output, then use them to create task agents:

# From CLI output - already set: # export CREDDY_URL=https://creddy-server.tail311b.ts.net # export CREDDY_CLIENT_ID=agent_9a57c4e6db3a # export CREDDY_CLIENT_SECRET=cks_0adf701f67231d2d08cd836c49574021 # Get admin token CREDDY_TOKEN=$(curl -s -X POST $CREDDY_URL/oauth/token \ -d "grant_type=client_credentials" \ -d "client_id=$CREDDY_CLIENT_ID" \ -d "client_secret=$CREDDY_CLIENT_SECRET" \ | jq -r .access_token) # Create a task agent with 4-hour TTL AGENT_CREDS=$(curl -s -X POST $CREDDY_URL/v1/admin/agents \ -H "Authorization: Bearer $CREDDY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "task-12345", "scopes": ["github:owner/repo"], "expires_in": "4h" }') # Extract credentials for the task agent AGENT_CLIENT_ID=$(echo $AGENT_CREDS | jq -r '.oidc.client_id') AGENT_CLIENT_SECRET=$(echo $AGENT_CREDS | jq -r '.oidc.client_secret') AGENT_URL=$(echo $AGENT_CREDS | jq -r '.server_url') # Pass to your agent process...

3. Agent Workflow

The task agent:

  1. Authenticates with its OIDC credentials
  2. Requests backend credentials as needed
  3. Does its work
  4. Self-deletes when done (or TTL expires as safety net)
# Agent receives these env vars from provisioner: # CREDDY_URL, CREDDY_CLIENT_ID, CREDDY_CLIENT_SECRET # Agent gets its own token CREDDY_TOKEN=$(curl -s -X POST $CREDDY_URL/oauth/token \ -d "grant_type=client_credentials" \ -d "client_id=$CREDDY_CLIENT_ID" \ -d "client_secret=$CREDDY_CLIENT_SECRET" \ | jq -r .access_token) # Get GitHub credential GITHUB_TOKEN=$(curl -s $CREDDY_URL/v1/credentials/github \ -H "Authorization: Bearer $CREDDY_TOKEN" \ | jq -r .token) # ... do work ... # Clean up curl -X DELETE $CREDDY_URL/v1/self \ -H "Authorization: Bearer $CREDDY_TOKEN"

Admin Scopes Reference

ScopePermission
admin:agents:readList agents
admin:agents:writeCreate/delete agents
admin:agents:*Both (recommended for provisioner)
admin:*Full admin access

See Concepts → Admin Scopes for the complete list.


Security Considerations

  1. Use TLS — Required for OIDC, recommended always
  2. Restrict network access — Firewall the port, only allow trusted agents
  3. Enable agent inactivity cleanup--agent-inactivity-days 30 removes stale enrollments
  4. Keep plugins updatedcreddy plugin outdated checks for updates

Next Steps

Last updated on

Apache 2.0 2026 © Creddy