Ctrl K
ComunidadGuías…

README.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# siteio

A self-hosted deployment platform for static websites and Docker containers with automatic HTTPS via Traefik.

## Installation

```bash
# macOS / Linux (official installer)
curl -LsSf https://houlahop.com/siteio/install | sh

# Or from this repo with Bun
bun install
bun run src/cli.ts --help
```

Windows binaries are not shipped in releases yet.

## Quick Start

Configure your client to connect to the siteio agent server:

```bash
siteio login --api-url https://api.yourdomain.com --api-key your-api-key
```

Or use a connection token:

```bash
siteio login --token <connection-token>
```

---

## Provision a server

Create a fresh Hetzner VM from your laptop, install the agent, and log in:

```bash
siteio config set hetznerToken <hetzner-cloud-token>
siteio server create mybox --sslip --email you@yourdomain.com --identity ~/.ssh/id_ed25519
```

Without `--sslip`, a configured Cloudflare token enables an interactive zone picker
with **Buy a new domain** as the last option:

```bash
siteio config set cloudflareToken <cloudflare-api-token>
siteio server create mybox
# Or use an existing zone without prompts:
siteio server create mybox --domain yourdomain.com --email you@yourdomain.com --identity ~/.ssh/id_ed25519
```

`HETZNER_TOKEN` (also `HCLOUD_TOKEN`) and `CLOUDFLARE_API_TOKEN` (also
`CLOUDFLARE_TOKEN`) override saved credentials. Config files are written with mode
0600 and tokens are masked by `config get` and `config set`, including JSON output.
The SSH public key must be next to its private key as `<identity>.pub`; multiple
keys in `~/.ssh` trigger a picker unless `--identity` is given.

By default the command resolves the cheapest currently available x86 VM type from
Hetzner's API in Falkenstein (`fsn1`) and uses the `docker-ce` app image. Override
with `--type <type>` and `--location <location>`. The VM is billable and its firewall
allows inbound TCP 22, 80 and 443. Custom wildcard DNS points directly to the VM.
Existing DNS with different settings is rejected; matching pre-existing records
are preserved during destruction.

Cloudflare requires Zone Read and DNS Edit permissions; buying also needs Registrar
Write and Account Settings Read for account discovery. Verify these permissions in
the dashboard when creating the token; the Registrar template key still needs live
dashboard validation. Purchases display the domain,
registration price and renewal price and require an explicit, non-refundable purchase
confirmation. Set up the account's payment method, default registrant contact and
Domain Registration Agreement in the Cloudflare dashboard first. API-supported TLDs
are checked at runtime; premium domains are not purchased. Auto-renew defaults to off.
See the [Cloudflare Registrar workflow](https://developers.cloudflare.com/registrar/registrar-api/).

Progress is saved in `~/.config/siteio/provisioned-servers/<name>.json` after each
step. Run `siteio server create mybox` again to resume. Omitted names default to
`siteio`. Keep the saved files: they identify resources owned by this command.
A pending or uncertain purchase is checked by domain status and is never submitted
again automatically. If Cloudflare reports a failed, blocked or action-required
registration, resolve it in the dashboard before resuming. DNS propagation, VM boot
and certificate issuance may require another run after a timeout.

```bash
siteio server destroy mybox
# For scripts, explicitly confirm destruction:
siteio server destroy mybox --yes
```

Destroy removes the VM, firewall, owned wildcard DNS and local login entry. It keeps
the domain registration and uploaded SSH key. Failed cleanup can be resumed with the
same command. `server` manages cloud infrastructure; `agent` manages software on a box.

---

## Try It Out

This repo includes working examples you can deploy immediately:

```bash
# Deploy the example static site
siteio sites deploy examples/static -n hello

# Deploy a pre-built Docker image
siteio apps create nginx-demo --image nginx:alpine --port 80
siteio apps deploy nginx-demo

# Build and deploy from Git (this repo!)
siteio apps create docker-demo \
  --git https://github.com/plosson/siteio \
  --context examples/docker \
  --port 3000
siteio apps deploy docker-demo
```

After deployment:
- Static site: `https://hello.yourdomain.com`
- Nginx demo: `https://nginx-demo.yourdomain.com`
- Docker demo: `https://docker-demo.yourdomain.com`

---

## Site Examples

### Example 1: Deploy a Website

Deploy a folder as a website:

```bash
siteio sites deploy ./my-website -n blog
```

This deploys your files to `https://blog.yourdomain.com`.

### Example 2: A Site with Auth, Database, and Storage

Every site ships with a PocketBase backend at `/api` — auth, database, file
storage, and realtime, no server code required:

```bash
siteio sites init ./todo   # scaffold: index.html + starter schema + AI guide
siteio sites dev           # run locally with the backend, no Docker
siteio sites deploy        # ship it
siteio sites admin         # backend dashboard URL + credentials
```

---

## Docker Container Examples

### Example 1: Simple Nginx Web Server

Deploy a basic Nginx container:

```bash
# Create the app
siteio apps create mysite --image nginx:alpine --port 80

# Deploy it
siteio apps deploy mysite
```

Available at `https://mysite.yourdomain.com`.

### Example 2: Deploy from Git Repository

Build and deploy directly from a Git repository:

```bash
# Create app from GitHub repo
siteio apps create myapi --git https://github.com/user/myapi --port 3000

# Deploy (clones repo, builds image, runs container)
siteio apps deploy myapi
```

With custom options:

```bash
# Specify branch and Dockerfile
siteio apps create myapi --git https://github.com/user/myapi \
  --branch develop \
  --dockerfile Dockerfile.prod \
  --port 3000

# Force rebuild without Docker cache
siteio apps deploy myapi --no-cache
```

#### Auto-deploy

A git app can redeploy itself. The agent checks the repository every 5 minutes;
nothing has to change in the repository.

```bash
# Redeploy on each new commit of the tracked branch
siteio apps set myapi --auto-deploy commit

# Redeploy on each higher release tag (vMAJOR.MINOR.PATCH only; v1.2.3-rc1 is ignored)
siteio apps set myapi --auto-deploy tag

# Stop
siteio apps set myapi --auto-deploy off
```

- In `tag` mode the tag itself is built, and an older tag never causes a downgrade.
- A manual `siteio apps deploy` still builds the branch HEAD. Use it to deploy a pre-release.
- A failed build leaves the running version up and is not retried until a newer
  commit or tag appears. `siteio apps info` shows the error.
- Compose apps are not supported.
- Set the interval with `SITEIO_AUTODEPLOY_INTERVAL` (seconds, default 300, minimum 60) on the agent, or with `autoDeployInterval` in the agent's `agent-config.json`. The env var wins when set and not empty.

### Example 3: Monorepo Deployment

Deploy a service from a monorepo by specifying the build context:

```bash
# Deploy backend service from monorepo
siteio apps create backend --git https://github.com/user/monorepo \
  --context services/backend \
  --dockerfile Dockerfile \
  --port 8080

siteio apps deploy backend
```

### Example 4: Node.js API with Environment Variables

Deploy a Node.js application with configuration:

```bash
# Create the app
siteio apps create nodeapi --image node:20-alpine --port 3000

# Configure environment variables
siteio apps set nodeapi \
  -e NODE_ENV=production \
  -e DATABASE_URL="postgres://user:pass@db.example.com:5432/mydb"

# Configure secrets (stored encrypted, never displayed again)
siteio apps set nodeapi --secret JWT_SECRET="your-secret-key"

# Set restart policy
siteio apps set nodeapi -r unless-stopped

# Deploy
siteio apps deploy nodeapi
```

### Secret environment variables

`-e KEY=value` is plain configuration: it is stored as-is and printed back by
`siteio apps info`. For anything sensitive — a passphrase, a database URL, an
API token, a signing key — use `--secret` instead:

```bash
# Inline
siteio apps set myapp --secret VAULT_PASSPHRASE="correct horse battery staple"

# From a file, keeping the value out of shell history and the process list
siteio apps set myapp --secret-file VAULT_PASSPHRASE=./passphrase.txt

# From stdin, same idea
pass show vault | siteio apps set myapp --secret-stdin VAULT_PASSPHRASE

# A whole env file at once — every key in it becomes a secret
siteio apps set myapp --secret ./secrets.env
```

The agent stops sending the value back once a key is marked secret, so the CLI
has nothing to print:

```console
$ siteio apps info myapp
Environment:
  NODE_ENV=production
  VAULT_PASSPHRASE=•••••••• (secret)
```

There is no flag to reveal it — a secret is write-only once set. To change one,
set it again; to remove it, `siteio apps unset myapp -e VAULT_PASSPHRASE`.
Restart the app for either to take effect.

What this is for: stopping the CLI from being the easy way to read every secret
of every app, and keeping values off your screen during a share or a demo. It
is not protection against someone with access to the server — the agent stores
the value as it stores any other env var, and the container needs it in its
environment, so `docker inspect` on the host still shows it.

### Example 5: PostgreSQL Database with Persistent Storage

Deploy PostgreSQL with a persistent volume:

```bash
# Create the app
siteio apps create postgres --image postgres:16-alpine --port 5432

# Configure with environment and volume
siteio apps set postgres \
  -e POSTGRES_USER=myuser \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -e POSTGRES_DB=myapp \
  -v pgdata:/var/lib/postgresql/data \
  -r always

# Deploy
siteio apps deploy postgres
```

### Example 6: Redis Cache with Custom Domain

Deploy Redis with a custom domain:

```bash
# Create the app
siteio apps create redis --image redis:7-alpine --port 6379

# Configure volume and custom domain
siteio apps set redis \
  -v redis-data:/data \
  -d cache.example.com \
  -r unless-stopped

# Deploy
siteio apps deploy redis
```

### Example 7: Full-Stack Application (Multiple Services)

Deploy a complete application stack:

```bash
# Backend API
siteio apps create backend --image myregistry/backend:latest --port 8080
siteio apps set backend \
  -e NODE_ENV=production \
  -e DATABASE_URL="postgres://user:pass@postgres.yourdomain.com:5432/app" \
  -e REDIS_URL="redis://redis.yourdomain.com:6379" \
  -v uploads:/app/uploads \
  -d api.example.com \
  -r unless-stopped
siteio apps deploy backend

# Background worker
siteio apps create worker --image myregistry/worker:latest --port 9000
siteio apps set worker \
  -e NODE_ENV=production \
  -e DATABASE_URL="postgres://user:pass@postgres.yourdomain.com:5432/app" \
  -e REDIS_URL="redis://redis.yourdomain.com:6379" \
  -r unless-stopped
siteio apps deploy worker
```

---

## Common Commands

```bash
# List all sites
siteio sites list

# List all apps
siteio apps list

# View app logs
siteio apps logs myapp --tail 100

# Stop an app
siteio apps stop myapp

# Restart an app
siteio apps restart myapp

# Bring a stopped app back (same image, no rebuild)
siteio apps start myapp

# Take a site offline (404) and bring it back
siteio sites stop mysite
siteio sites start mysite

# Remove an app
siteio apps rm myapp

# Remove a site
siteio sites rm mysite

# Open the in-site live editor: chat with an AI editor on the site itself and
# watch changes land in place (requires an LLM credential configured on the agent)
siteio sites edit mysite --open

# Revoke all outstanding editor links for a site
siteio sites edit mysite --revoke
```

## JSON Output

All commands support `--json` for scripting:

```bash
siteio --json sites list
siteio --json apps info myapp
```