11# Catapult
22
3- Automated deployment runner for GitHub webhooks. Handles PR preview deployments and main branch deployments with Nix-based build isolation and multi-environment support.
3+ [ ![ CI] ( https://github.com/nullisLabs/catapult/actions/workflows/ci.yml/badge.svg )] ( https://github.com/nullisLabs/catapult/actions/workflows/ci.yml )
4+ [ ![ License: AGPL-3.0] ( https://img.shields.io/badge/License-AGPL--3.0-blue.svg )] ( https://www.gnu.org/licenses/agpl-3.0 )
5+ [ ![ Rust] ( https://img.shields.io/badge/rust-1.75%2B-orange.svg )] ( https://www.rust-lang.org )
6+ [ ![ NixOS] ( https://img.shields.io/badge/NixOS-ready-5277C3.svg )] ( https://nixos.org )
47
5- ## Architecture Overview
8+ Preview deploys without the Vercel price tag. Nix builds, your servers, zero BS.
9+
10+ ## Overview
611
712Catapult uses a ** central + worker** architecture:
813
14+ - ** Central** receives GitHub webhooks, manages configuration, and dispatches jobs
15+ - ** Workers** execute builds in isolated Podman containers and deploy to Caddy
16+
917```
10- GitHub App (single application)
11- ↓ webhooks
12- ┌─────────────────────────────────────────────────────────────┐
13- │ Catapult Central (catapult.nullislabs.io) │
14- │ ├─ Receives all GitHub webhooks │
15- │ ├─ Verifies webhook signatures │
16- │ ├─ Looks up deployment config (PostgreSQL) │
17- │ ├─ Generates GitHub installation access tokens │
18- │ ├─ Posts "Building..." comment to PR │
19- │ └─ Dispatches build jobs to appropriate worker │
20- └─────────────────────────────────────────────────────────────┘
21- ↓ authenticated job dispatch
22- ┌───────────────┴───────────────┐
23- ↓ ↓
24- ┌─────────────────────────┐ ┌─────────────────────────┐
25- │ Caddy Container │ │ Caddy Container │
26- │ (nullislabs) │ │ (nullispl) │
27- │ ┌─────────────────────┐ │ │ ┌─────────────────────┐ │
28- │ │ Catapult Worker │ │ │ │ Catapult Worker │ │
29- │ │ deployer.nullislabs │ │ │ │ deployer.nullis.pl │ │
30- │ │ .io │ │ │ │ │ │
31- │ │ - Clones repo │ │ │ │ - Clones repo │ │
32- │ │ - Builds (Podman) │ │ │ │ - Builds (Podman) │ │
33- │ │ - Deploys files │ │ │ │ - Deploys files │ │
34- │ │ - Configures Caddy │ │ │ │ - Configures Caddy │ │
35- │ └─────────────────────┘ │ │ └─────────────────────┘ │
36- │ Caddy Server │ │ Caddy Server │
37- └─────────────────────────┘ └─────────────────────────┘
38- ↓ status updates
39- ┌─────────────────────────────────────────────────────────────┐
40- │ Catapult Central │
41- │ └─ Posts success/failure comment to PR │
42- └─────────────────────────────────────────────────────────────┘
18+ GitHub ──webhook──▶ Central ──dispatch──▶ Worker ──deploy──▶ Caddy
19+ │ │
20+ ▼ ▼
21+ PostgreSQL Podman + Nix
4322```
4423
45- ## Components
46-
47- ### Catapult Central (` catapult.nullislabs.io ` )
48-
49- The orchestrator that handles GitHub integration:
50-
51- - Receives webhooks from the GitHub App
52- - Verifies webhook signatures
53- - Manages deployment configuration database
54- - Generates short-lived GitHub installation tokens
55- - Dispatches jobs to environment-specific workers
56- - Posts PR comments (building, success, failure)
57-
58- ### Catapult Worker (` deployer.<zone> ` )
59-
60- Runs inside each Caddy container, executes builds and deployments:
61-
62- - Receives authenticated build jobs from Central
63- - Clones repositories (using provided GitHub token)
64- - Runs builds in isolated Podman containers (NixOS-based)
65- - Writes build artifacts to ` /var/www/sites/ `
66- - Configures Caddy routes via admin API (localhost:2019)
67- - Reports status back to Central
68-
69- ** Single binary, two modes:**
24+ Single binary, two modes:
7025``` bash
7126catapult central # Run as orchestrator
7227catapult worker # Run as build executor
7328```
7429
75- ## Key Features
76-
77- - ** Single GitHub App** - One app installation covers all environments
78- - ** Multi-environment support** - Deploy to different Caddy instances
79- - ** Private repository support** - Uses GitHub App installation access tokens
80- - ** PR preview deployments** - Automatic previews for every PR
81- - ** Main branch deployments** - Automatic production deployments
82- - ** Automatic cleanup** - Removes PR deployments on merge/close
83- - ** Nix-based build isolation** - Podman containers with flake-defined environments
84- - ** Custom build commands** - Via ` .deploy.json ` in repository
85-
86- ## Build System
87-
88- Workers use ** Podman** to run isolated build containers. Each container runs a minimal NixOS image that uses ** Nix flakes** to bring up the appropriate build environment.
89-
90- ```
91- Catapult Worker (deployer.<zone>)
92- ↓
93- Podman (container-in-container)
94- ↓
95- NixOS Container
96- ├─ nix develop (from build flake)
97- ├─ git clone (with token)
98- ├─ Run build command
99- └─ Output artifacts → /var/www/sites/
100- ```
101-
102- ### Build Flakes
103-
104- | Type | Flake | Provides |
105- | ------| -------| ----------|
106- | ` sveltekit ` | ` github:nullisLabs/catapult#sveltekit ` | Node.js, npm |
107- | ` vite ` | ` github:nullisLabs/catapult#vite ` | Node.js, npm |
108- | ` zola ` | ` github:nullisLabs/catapult#zola ` | Zola static site generator |
109- | ` custom ` | (from repo's flake.nix) | User-defined |
110- | ` auto ` | (detected) | Based on repo contents |
111-
112- ## Configuration
113-
114- ### Central Environment Variables
115-
116- ``` bash
117- # Database
118- DATABASE_URL=postgresql://user:pass@host:5432/dbname
119-
120- # GitHub App
121- GITHUB_APP_ID=123456
122- GITHUB_PRIVATE_KEY_PATH=/path/to/private-key.pem
123- GITHUB_WEBHOOK_SECRET=your-webhook-secret
124-
125- # Server
126- LISTEN_ADDR=0.0.0.0:8080
127-
128- # Worker authentication
129- WORKER_SHARED_SECRET=your-shared-secret
130- ```
131-
132- ### Worker Environment Variables
30+ ## Features
13331
134- ``` bash
135- # Central connection
136- CENTRAL_URL=https://catapult.nullislabs.io
137- WORKER_SHARED_SECRET=your-shared-secret
32+ - ** PR Preview Deployments** - Automatic previews at ` pr-{N}-{repo}.example.com `
33+ - ** Production Deployments** - Deploy on push to main branch
34+ - ** Multi-tenant** - Route deployments to different workers by zone
35+ - ** Nix Build Isolation** - Reproducible builds in Podman containers
36+ - ** GitHub App Integration** - Private repo support, PR comments
37+ - ** Cloudflare Tunnel Support** - Optional DNS and tunnel management
13838
139- # Server
140- LISTEN_ADDR=0.0.0.0:8080
39+ ## Quick Start
14140
142- # Build system
143- PODMAN_SOCKET=/run/podman/podman.sock
41+ ### Repository Configuration
14442
145- # Caddy
146- CADDY_ADMIN_API=http://localhost:2019
147- SITES_DIR=/var/www/sites
148- ```
149-
150- ## Repository Configuration
151-
152- Repositories can include a ` .deploy.json ` file:
43+ Add ` .deploy.json ` to your repository:
15344
15445``` json
15546{
@@ -159,72 +50,69 @@ Repositories can include a `.deploy.json` file:
15950}
16051```
16152
162- ### Build Types
163-
164- | Type | Default Command | Output Dir |
165- | ------| -----------------| ------------|
166- | ` sveltekit ` | ` npm run build ` | ` build ` |
167- | ` vite ` | ` npm run build ` | ` dist ` |
168- | ` zola ` | ` zola build ` | ` public ` |
169- | ` custom ` | (from config) | (from config) |
170- | ` auto ` | (detected) | (detected) |
53+ Supported build types: ` sveltekit ` , ` vite ` , ` zola ` , ` custom ` , ` auto `
17154
172- ## URL Structure
173-
174- ### PR Deployments
175- ```
176- https://pr-{number}-{repo}.{domain}/
55+ ### Organization Defaults
17756
178- Examples:
179- https://pr-42-website.wilmen.co/
180- https://pr-123-docs.nullis.xyz/
181- ```
57+ Add ` .deploy.json ` to ` {org}/.github/ ` for organization-wide defaults:
18258
183- ### Main Branch Deployments
184- ```
185- https://{subdomain}.{domain}/
186- or
187- https://{domain}/
59+ ``` json
60+ {
61+ "zone" : " production" ,
62+ "domain_pattern" : " {repo}.example.com" ,
63+ "pr_pattern" : " pr-{pr}-{repo}.example.com"
64+ }
18865```
18966
190- ## Security
191-
192- ### GitHub App Permissions
67+ ## Deployment
19368
194- - Contents: Read (clone repos)
195- - Pull Requests: Read & Write (comment on PRs)
69+ See [ docs/deployment.md] ( docs/deployment.md ) for NixOS deployment instructions.
19670
197- ### Central ↔ Worker Authentication
71+ ### NixOS Flake
19872
199- Workers authenticate with Central using a shared secret (HMAC-signed requests).
73+ ``` nix
74+ {
75+ inputs.catapult.url = "github:nullisLabs/catapult";
76+
77+ outputs = { self, nixpkgs, catapult, ... }: {
78+ nixosConfigurations.myserver = nixpkgs.lib.nixosSystem {
79+ modules = [
80+ catapult.nixosModules.default
81+ {
82+ services.catapult.central = {
83+ enable = true;
84+ databaseUrl = "postgresql://catapult@localhost/catapult";
85+ githubAppId = 123456;
86+ # ... see docs/deployment.md for full options
87+ };
88+ }
89+ ];
90+ };
91+ };
92+ }
93+ ```
20094
201- ### Build Isolation
95+ ## Architecture
20296
203- Builds run in isolated Podman containers with:
204- - NixOS-based minimal image
205- - Read-only root filesystem (except build directory)
206- - Network restrictions (blocks RFC1918, allows internet)
207- - Memory/CPU limits
208- - PID limits (prevent fork bombs)
209- - Dropped capabilities
97+ See [ docs/architecture.md] ( docs/architecture.md ) for detailed diagrams and API documentation.
21098
21199## Development
212100
213101``` bash
214102# Enter development environment
215103nix develop
216104
217- # Run central
218- cargo run -- central
219-
220- # Run worker
221- cargo run -- worker
105+ # Build
106+ cargo build
222107
223108# Run tests
224109cargo test
225110
226111# Watch mode
227112cargo watch -x " run -- central"
113+
114+ # Run all CI checks
115+ just ci
228116```
229117
230118## License
0 commit comments