00503b4c0a
New zero-dependency Go CLI (cmd/cli) that drives the existing HTTP API: login/logout, apps list, deploy (synchronous, --timeout), logs (one-shot + -f SSE follow), and status. Caches a 24h JWT in ~/.tinyforge/config.json (0600, Chmod-enforced on overwrite); Bearer-header auth keeps the token out of server/proxy logs; no-echo password prompt (kernel32 on Windows, stty elsewhere). Server/token resolved via flags, TINYFORGE_URL/TINYFORGE_TOKEN env, or config. README CLI section + root-anchored .gitignore entries for the build output.
185 lines
7.8 KiB
Markdown
185 lines
7.8 KiB
Markdown
# Tinyforge
|
|
|
|
Self-hosted deployment platform with a web dashboard. Deploy Docker containers from registries with zero-downtime blue-green strategy, host static sites and Deno APIs directly from Git repositories, and manage reverse proxy configuration — all from a single binary.
|
|
|
|
## Features
|
|
|
|
### Container Deployments
|
|
|
|
- **Registry polling** and **webhook receiver** for automatic deployments
|
|
- **Blue-green deploys** with health checks and automatic rollback
|
|
- **Multi-stage projects** (dev, staging, prod) with tag pattern matching
|
|
- **Real-time deploy logs** via SSE streaming
|
|
|
|
### Branch Preview Environments
|
|
|
|
Get an isolated, throwaway deploy for every feature branch:
|
|
|
|
- Add a **branch pattern** (e.g. `feat/*`) to a workload's **git trigger** (Triggers panel → git trigger → *Branch pattern*).
|
|
- Pushing to any branch matching the pattern deploys an **isolated per-branch preview** — a child workload that inherits the source config, served at a **slug-prefixed subdomain** (`feat-login-app.example.com`) so previews never collide with each other or the main deploy.
|
|
- Previews are **automatically torn down** when the branch is deleted upstream.
|
|
- Manage live previews from the app's **Preview environments** panel (`/apps/[id]`): open each branch's URL or tear it down manually. A torn-down preview is recreated on the next push to its branch.
|
|
|
|
### Static Sites
|
|
|
|
Deploy static sites and Deno-powered APIs directly from Git repositories:
|
|
|
|
- **Git providers**: Gitea/Forgejo, GitHub, and GitLab (public and private repos)
|
|
- **Static mode**: Serves HTML/CSS/JS via nginx container
|
|
- **Deno mode**: Full-stack with TypeScript API backend + static frontend — API routes are auto-discovered from `/api` folder using a naming convention (`API_get_users`, `API_post_items`, etc.)
|
|
- **Markdown rendering**: Optionally converts `.md` files to styled HTML
|
|
- **Branch & folder picker**: Select any branch and subfolder as the deployment root
|
|
- **Auto-sync**: Trigger redeployment on push or tag events, or manually
|
|
- **Per-site secrets**: Encrypted environment variables injected at runtime
|
|
|
|
### Infrastructure
|
|
|
|
- **NPM / Traefik integration** for automatic reverse proxy and SSL configuration
|
|
- **Cloudflare DNS** sync for automatic DNS record management
|
|
- **Volume management**: Create, browse, upload, and download Docker volumes
|
|
- **Stale container cleanup**: Detect and remove unused containers
|
|
- **Image management**: List and prune unused Docker images
|
|
- **Database backups**: Scheduled and manual backups with one-click restore
|
|
- **Config export/import**: YAML-based seed configuration for reproducible setups
|
|
|
|
### Auth & Security
|
|
|
|
- **Local auth** with bcrypt password hashing
|
|
- **OIDC/SSO** support for single sign-on
|
|
- **Encrypted credential storage** (AES-256-GCM)
|
|
- **Role-based access**: Admin and user roles
|
|
|
|
## Prerequisites
|
|
|
|
- Docker with Docker Compose
|
|
- A Docker network for deployed containers (e.g. `staging-net`)
|
|
- Nginx Proxy Manager (optional, for automatic proxy configuration)
|
|
- Wildcard DNS pointing to your server (for subdomain-based routing)
|
|
|
|
## Quick Start
|
|
|
|
1. **Create the Docker network** (containers will be attached to this):
|
|
|
|
```bash
|
|
docker network create staging-net
|
|
```
|
|
|
|
2. **Create a `.env` file** (see `.env.example`):
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
# Edit .env and set ENCRYPTION_KEY and ADMIN_PASSWORD
|
|
# Generate a key: openssl rand -hex 32
|
|
```
|
|
|
|
3. **Start Tinyforge**:
|
|
|
|
```bash
|
|
docker compose up -d
|
|
```
|
|
|
|
4. **Open the dashboard** at `http://localhost:8080` and log in with `admin` / your `ADMIN_PASSWORD`.
|
|
|
|
## Configuration
|
|
|
|
### Environment Variables
|
|
|
|
| Variable | Required | Description |
|
|
| ------------------ | ------------------- | -------------------------------------------------------------------------------- |
|
|
| `ENCRYPTION_KEY` | Yes | AES-256 key for encrypting stored credentials. Use `openssl rand -hex 32` |
|
|
| `ADMIN_PASSWORD` | Yes (first launch) | Password for the default admin user |
|
|
| `SEED_FILE` | No | Path to YAML seed config (default: `./tinyforge.yaml`) |
|
|
| `DATA_DIR` | No | SQLite database directory (default: `./data`) |
|
|
| `LISTEN_ADDR` | No | HTTP listen address (default: `:8080`) |
|
|
| `NPM_URL` | No | Override NPM API URL (otherwise uses value from settings) |
|
|
| `POLLING_INTERVAL` | No | Registry polling interval, Go duration string e.g. `5m` (default from settings) |
|
|
|
|
### Seed Config
|
|
|
|
On first launch, Tinyforge imports a YAML seed file to pre-configure registries, projects, and settings. See `tinyforge.example.yaml` for the full format.
|
|
|
|
### Webhook Integration
|
|
|
|
After setup, find your webhook URL at **Settings > Webhook URL** in the dashboard. Configure your CI/CD (Gitea Actions, GitHub Actions) to POST to this URL on image push:
|
|
|
|
```bash
|
|
curl -X POST https://your-domain/api/webhook/<secret> \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"image": "registry.example.com/org/app:v1.2.3"}'
|
|
```
|
|
|
|
### OIDC Setup
|
|
|
|
1. Go to **Settings > Auth** in the dashboard
|
|
2. Switch auth mode to **OIDC**
|
|
3. Enter your provider's Issuer URL, Client ID, and Client Secret
|
|
4. Set the Redirect URL to `https://your-domain/api/auth/oidc/callback`
|
|
|
|
## CLI
|
|
|
|
`tinyforge` is a terminal client for driving a server from the shell, built on the same HTTP API as the web UI.
|
|
|
|
### Build
|
|
|
|
```bash
|
|
go build -o tinyforge ./cmd/cli # ./tinyforge (tinyforge.exe on Windows)
|
|
```
|
|
|
|
### Usage
|
|
|
|
```bash
|
|
# Log in once — caches a 24h token in ~/.tinyforge/config.json (mode 0600)
|
|
tinyforge login --base-url http://localhost:8090
|
|
# ...or non-interactively (no password echo / shell-history leak):
|
|
TINYFORGE_PASSWORD=… tinyforge login --base-url http://localhost:8090 --user admin
|
|
|
|
tinyforge apps # list apps + container state
|
|
tinyforge deploy my-app # deploy and wait for completion
|
|
tinyforge deploy my-app --ref v1.2.3 --note "hotfix"
|
|
tinyforge logs my-app -f # follow logs (Ctrl-C to stop)
|
|
tinyforge status # server health + current user
|
|
tinyforge status my-app # one app's containers
|
|
tinyforge logout # revoke + clear the cached token
|
|
```
|
|
|
|
### Server & token resolution
|
|
|
|
| Setting | Flag | Env | Default |
|
|
| -------- | ------------ | ----------------- | ------------------------ |
|
|
| Base URL | `--base-url` | `TINYFORGE_URL` | `http://localhost:8080` |
|
|
| Token | `--token` | `TINYFORGE_TOKEN` | cached by `login` |
|
|
| Config | `--config` | `TINYFORGE_CONFIG`| `~/.tinyforge/config.json` |
|
|
|
|
### Notes
|
|
|
|
- Login returns a **24h JWT** — there is no long-lived API token yet, so unattended use re-logs in when the token expires. `deploy` / `stop` / `start` require an **admin** account.
|
|
- The token is sent as an `Authorization: Bearer` header (never placed in the URL) and the config file is written with `0600` permissions.
|
|
|
|
## Development
|
|
|
|
```bash
|
|
# Build frontend
|
|
cd web && npm install && npm run build && cd ..
|
|
|
|
# Run backend (requires ENCRYPTION_KEY and ADMIN_PASSWORD env vars)
|
|
go run ./cmd/server
|
|
|
|
# Or use Make
|
|
make build
|
|
make dev
|
|
```
|
|
|
|
## Architecture
|
|
|
|
```text
|
|
CI/Registry --> Webhook/Poller --> Deployer --> Docker + NPM
|
|
|
|
|
Git Repo ----> Static Sites -------> Docker + NPM
|
|
|
|
|
Event Bus --> SSE --> Web Dashboard
|
|
```
|
|
|
|
- **Backend**: Go 1.24, chi router, SQLite (pure Go), Docker SDK
|
|
- **Frontend**: SvelteKit 2, Tailwind CSS 4, TypeScript
|
|
- **Deployment**: Single binary with embedded SPA, multi-stage Dockerfile
|