255 lines
5.9 KiB
Markdown
255 lines
5.9 KiB
Markdown
# Update Server
|
|
|
|
Self-hosted server for publishing application updates. An administrator uploads
|
|
versioned release artifacts through a web UI, and client applications discover
|
|
and download allowed updates through a bearer-authenticated HTTP API.
|
|
|
|
The project is designed for small private deployments: one Go application, one
|
|
SQLite database, local artifact storage, and HTTPS termination by a reverse
|
|
proxy such as Caddy or Nginx.
|
|
|
|
## What It Does
|
|
|
|
- Admin web UI at `/admin`.
|
|
- Project and tag management.
|
|
- Release artifact upload per project.
|
|
- Client API key management with project or tag scope rules.
|
|
- Client API at `/api/v1`.
|
|
- Private artifact downloads through the application, not through a public file
|
|
directory.
|
|
- SQLite migrations applied automatically on startup.
|
|
- Docker image and Docker Compose deployment files.
|
|
|
|
## Current Readiness
|
|
|
|
This is a usable MVP. It is ready to run locally or on a small server with
|
|
Docker, create an admin user, create projects, upload releases, issue API keys,
|
|
and let clients check and download updates.
|
|
|
|
You do not need to prepare a separate database or run a separate migration step.
|
|
The container stores SQLite and uploaded artifacts under `/data`, and the app
|
|
applies migrations on startup.
|
|
|
|
You do need:
|
|
|
|
- Docker with Docker Compose;
|
|
- `APP_BASE_URL`, `ADMIN_EMAIL`, and `ADMIN_PASSWORD`;
|
|
- a persistent `/data` volume;
|
|
- for public HTTPS: a reverse proxy in front of the app.
|
|
|
|
Post-MVP features such as release channels, signed manifests, delta updates,
|
|
S3-compatible storage, and multi-user administration are not part of the current
|
|
minimal version.
|
|
|
|
## Quick Start With Docker Compose
|
|
|
|
1. Copy the example environment file:
|
|
|
|
```bash
|
|
cp deploy/update-server.env.example .env
|
|
```
|
|
|
|
2. Edit `.env`.
|
|
|
|
For a local first run:
|
|
|
|
```env
|
|
APP_BASE_URL=http://127.0.0.1:8080
|
|
ADMIN_EMAIL=admin@example.com
|
|
ADMIN_PASSWORD=change-this-before-production
|
|
```
|
|
|
|
For production behind HTTPS:
|
|
|
|
```env
|
|
APP_BASE_URL=https://updates.example.com
|
|
ADMIN_EMAIL=admin@example.com
|
|
ADMIN_PASSWORD=use-a-real-password
|
|
```
|
|
|
|
If `APP_BASE_URL` starts with `https://`, open the admin UI through that
|
|
HTTPS URL. Secure cookies are enabled automatically for HTTPS base URLs.
|
|
|
|
3. Build and start the container:
|
|
|
|
```bash
|
|
docker compose up -d --build
|
|
```
|
|
|
|
4. Check that it is alive:
|
|
|
|
```bash
|
|
curl http://127.0.0.1:8080/healthz
|
|
```
|
|
|
|
5. Open the admin UI:
|
|
|
|
```text
|
|
http://127.0.0.1:8080/admin
|
|
```
|
|
|
|
After login, create a project, upload a release, create an API key with download
|
|
permission, and use that key from a client.
|
|
|
|
## Docker Run Example
|
|
|
|
Docker Compose is the recommended path, but a direct Docker run works too:
|
|
|
|
```bash
|
|
docker build -t update-server:latest .
|
|
|
|
docker volume create update-server-data
|
|
|
|
docker run -d \
|
|
--name update-server \
|
|
--restart unless-stopped \
|
|
-p 127.0.0.1:8080:8080 \
|
|
-e APP_ADDR=0.0.0.0:8080 \
|
|
-e APP_BASE_URL=http://127.0.0.1:8080 \
|
|
-e DATA_DIR=/data \
|
|
-e SQLITE_PATH=/data/db.sqlite \
|
|
-e ARTIFACTS_DIR=/data/artifacts \
|
|
-e MIGRATIONS_DIR=/app/migrations \
|
|
-e TEMPLATES_DIR=/app/web/templates \
|
|
-e STATIC_DIR=/app/web/static \
|
|
-e TRUST_PROXY_HEADERS=false \
|
|
-e ADMIN_EMAIL=admin@example.com \
|
|
-e ADMIN_PASSWORD=change-this-before-production \
|
|
-v update-server-data:/data \
|
|
update-server:latest
|
|
```
|
|
|
|
## Proxmox / Caddy Example
|
|
|
|
A simple home-server layout is:
|
|
|
|
```text
|
|
Internet
|
|
-> router port forward 80/443
|
|
-> Caddy reverse proxy LXC
|
|
-> Docker tools LXC running update-server
|
|
```
|
|
|
|
Example:
|
|
|
|
```text
|
|
Caddy LXC: 192.168.1.50
|
|
Docker tools LXC: 192.168.1.130
|
|
Update Server: 192.168.1.130:18080
|
|
Public URL: https://updates.esenin.site
|
|
```
|
|
|
|
In this layout, publish the container port on the Docker tools LXC address:
|
|
|
|
```yaml
|
|
ports:
|
|
- "192.168.1.130:18080:8080"
|
|
```
|
|
|
|
Set production environment values:
|
|
|
|
```env
|
|
APP_BASE_URL=https://updates.esenin.site
|
|
ADMIN_EMAIL=admin@example.com
|
|
ADMIN_PASSWORD=use-a-real-password
|
|
```
|
|
|
|
Then point Caddy at the internal service:
|
|
|
|
```caddyfile
|
|
updates.esenin.site {
|
|
encode gzip zstd
|
|
|
|
request_body {
|
|
max_size 1GB
|
|
}
|
|
|
|
reverse_proxy 192.168.1.130:18080
|
|
}
|
|
```
|
|
|
|
The admin UI and API can live on the same domain:
|
|
|
|
```text
|
|
https://updates.esenin.site/admin
|
|
https://updates.esenin.site/api/v1
|
|
```
|
|
|
|
## Client API
|
|
|
|
The API entrypoint is:
|
|
|
|
```text
|
|
GET /api/v1
|
|
```
|
|
|
|
Protected client endpoints require:
|
|
|
|
```http
|
|
Authorization: Bearer <api_key>
|
|
```
|
|
|
|
Common endpoints:
|
|
|
|
```text
|
|
GET /api/v1/projects
|
|
GET /api/v1/projects/{projectSlug}/releases/latest
|
|
GET /api/v1/releases/{releaseID}
|
|
GET /api/v1/releases/{releaseID}/download
|
|
```
|
|
|
|
Example:
|
|
|
|
```bash
|
|
curl \
|
|
-H "Authorization: Bearer upsk_replace_me" \
|
|
https://updates.example.com/api/v1/projects
|
|
```
|
|
|
|
Downloads are intentionally private: uploaded files should not be served by
|
|
Caddy or Nginx as static files. Clients download through the application so API
|
|
key permissions and project scopes are enforced.
|
|
|
|
## Data And Backups
|
|
|
|
Persist the whole `/data` directory or Docker volume. It contains:
|
|
|
|
```text
|
|
/data/db.sqlite
|
|
/data/db.sqlite-wal
|
|
/data/db.sqlite-shm
|
|
/data/artifacts/...
|
|
```
|
|
|
|
For live backups, prefer SQLite's online backup command for the database and
|
|
archive `/data/artifacts` separately. See `docs/DEPLOYMENT.md` for a fuller
|
|
backup and restore flow.
|
|
|
|
## Development
|
|
|
|
Useful local commands:
|
|
|
|
```bash
|
|
just run
|
|
just test
|
|
just build
|
|
```
|
|
|
|
Without `just`:
|
|
|
|
```bash
|
|
go run ./cmd/server
|
|
go test ./...
|
|
go build -o .bin/update-server ./cmd/server
|
|
```
|
|
|
|
Local defaults use `data-dev/` and `http://127.0.0.1:8080` unless overridden by
|
|
environment variables.
|
|
|
|
## More Docs
|
|
|
|
- `docs/DEPLOYMENT.md` - deployment, reverse proxy, backup, and restore notes.
|
|
- `deploy/update-server.env.example` - production environment example.
|
|
- `deploy/Caddyfile.example` - Caddy reverse proxy example.
|
|
- `deploy/nginx.update-server.conf.example` - Nginx reverse proxy example.
|
|
- `example/autoupdate.py` - minimal Python auto-update client helper.
|