add readme
This commit is contained in:
parent
b15b95781c
commit
bcef2d7b52
1 changed files with 255 additions and 0 deletions
255
README.md
Normal file
255
README.md
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
# 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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue