diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 0000000..7729d54 --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,72 @@ +# Development + +## Makefile targets + +```txt +Usage: make [target1] [target2] ... + +Commands/Targets: +help show this message +install install project +update update project dependencies +format format project +lint lint project +build build project +start start server in localhost +test test project +test-% test project with specific test +coverage test project with coverage +uv-sync uv sync +uv-upgrade uv sync upgrade +ruff ruff check +ruff-fix ruff check (and fix) +ruff-format ruff format +ruff-format-check ruff format (check only) +ty ty check +unittest unittest +unittest-% unittest -k [filter] +coverage-unittest coverage run -m unittest +coverage-report coverage report +coverage-html coverage html +coverage-xml coverage xml +docker-build docker build +docker-run docker run +``` + +## TODO + +- [x] basic http server +- [x] docker container +- [x] env instead of args when available +- [x] PUT gzip data into /data/xxx +- [x] DELETE request +- [x] max file size +- [x] .host in /data/xxx can be translated as host in GET / +- [x] header to setup .host file instead of in archive +- [x] ignore .gitignore/.host etc at root +- [x] cerbot install in container + path env/arg +- [x] redirect /.well-known/acme-challenge to specific path +- [x] certbot/self-signed create/renew in specific dir +- [x] better logger +- [x] renew command +- [x] https mode w/ multiple hosts +- [x] create certificate on request +- [x] certbot copy certificates for unique path +- [x] better error page +- [x] add favicon.ico + special path +- [x] [http.server security](https://docs.python.org/3/library/http.server.html#http-server-security) +- [x] launch separate upgrade 80->443 server when https +- [x] token management with "generate" command and bind path to specific token +- [x] docker compose example + .env +- [x] 404 GET on host not found +- [x] 403 PUT on host already taken +- [x] remove dot files after file extract +- [x] unit tests +- [x] github actions +- [x] X-Redirect +- [x] X-Proxy +- [ ] detect root certificate change and update server +- [ ] detect tokens change and update token_manager +- [ ] allow args before/after command +- [x] proper doc + diff --git a/README.md b/README.md index f205e7d..1699bcb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,53 @@ -# Stapler +# Stapler + +*Static pages as simple as a gzip file* ![logo.svg](logo.svg) +## Table of Contents + +- [What is Stapler](#what-is-stapler) +- [Python CLI](#python-cli) + - [Basic usage](#basic-usage) +- [HTTP API](#http-api) + - [Create/update page from gzip](#createupdate-page-from-gzip) + - [Create/update page with redirect](#createupdate-page-with-redirect) + - [Create/update page with proxy](#createupdate-page-with-proxy) + - [Delete page](#delete-page) +- [Docker](#docker) + + +## What is Stapler + +Stapler is a **static page delivery server**. + +You feed it a tar.gz file of your content, and it serves it at your desired path or host. + +It handles: + +* static files delivery: `/path/xxx` +* directory roots translation into `index.html` (if existing) +* host translation to specific path: `my.example.com => /path/` +* auto host discovery and certificate issuing (via certbot) +* redirect pages: `/path-2/ => (redirect) https://my-website.com` +* proxy pages: `/path-3/ => https://my-website.com` +* updating/deleting content via API with `curl` + +## Python CLI + +### Basic usage + +Theres 3 basic commands for the stapler server: + +* `run`: launch the server to serve at the desired paths (see full CLI help for env vars and such) +* `renew`: renew all existing certificates (the server must be running in the background) +* `token`: generate a new secure API token + +See [Docker](#docker) for a quick deployable server. + +
+ Full CLI Help + ```txt usage: stapler [-h] [--debug | --no-debug] [-d DATA_DIR] [--certificates | --no-certificates] [--certbot | --no-certbot] [--self-signed-path SELF_SIGNED_PATH] [--certbot-conf CERTBOT_CONF] [--certbot-www CERTBOT_WWW] @@ -47,22 +93,34 @@ options: (Each option can be supplied with equivalent environment variable.) ``` -## Endpoints +
-### Create/update page +## HTTP API + +### Create/update page from gzip ```txt PUT /{page}/ + X-Token (your API token) + X-Host (optional host as entrypoint) + (body with tar data) ``` ```bash -# create archive from 'dist' dir and upload to /my-project/ -tar -czC dist . | curl -X PUT \ - --data-binary @- \ +# create archive from 'dist' dir and upload it to /my-project/ +tar -czC dist -f dist.tar.gz . +curl -X PUT \ -H 'X-Token: ' \ + --data-binary "@dist.tar.gz" \ https://stapler-host/my-project/ -# create archive from 'dist' dir and upload to /my-project/ and myproject.example.com +# same thing but one-liner +tar -czC dist . | curl -X PUT \ + -H 'X-Token: ' \ + --data-binary @- \ + https://stapler-host/my-project/ + +# make stapler server identifiers myproject.example.com as /my-project/ tar -czC dist . | curl -X PUT \ --data-binary @- \ -H 'X-Token: ' \ @@ -70,10 +128,52 @@ tar -czC dist . | curl -X PUT \ https://stapler-host/my-project/ ``` +### Create/update page with redirect + +```txt +PUT /{page}/ + X-Token (your API token) + X-Redirect (redirection target) + X-Host (optional host as entrypoint) +``` + +```bash +# create /my-project/ that redirects to https://github.com/my-project +curl -X PUT \ + -H 'X-Token: ' \ + -H 'X-Redirect: https://github.com/my-project' \ + https://stapler-host/my-project/ + +# simple redirect from root host to www +curl -X PUT \ + -H 'X-Token: ' \ + -H 'X-Proxy: https://www.my-website.com' \ + -H 'X-Host: my-website.com' \ + https://stapler-host/my-website-www/ +``` + +### Create/update page with proxy + +```txt +PUT /{page}/ + X-Token (your API token) + X-Proxy (proxy target) + X-Host (optional host as entrypoint) +``` + +```bash +# create /my-website/ that proxies to http://localhost:8000 +curl -X PUT \ + -H 'X-Token: ' \ + -H 'X-Proxy: http://localhost:8000' \ + https://stapler-host/my-project/ +``` + ### Delete page ```txt DELETE /{page}/ + X-Token (your API token) ``` ```bash @@ -83,71 +183,19 @@ curl -X DELETE \ https://stapler-host/my-project/ ``` -## Development +## Docker -### TODO +Stapler ships with a deploy-ready `Dockerfile` and a sample `docker compose` stack with: -- [x] basic http server -- [x] docker container -- [x] env instead of args when available -- [x] PUT gzip data into /data/xxx -- [x] DELETE request -- [x] max file size -- [x] .host in /data/xxx can be translated as host in GET / -- [x] header to setup .host file instead of in archive -- [x] ignore .gitignore/.host etc at root -- [x] cerbot install in container + path env/arg -- [x] redirect /.well-known/acme-challenge to specific path -- [x] certbot/self-signed create/renew in specific dir -- [x] better logger -- [x] renew command -- [x] https mode w/ multiple hosts -- [x] create certificate on request -- [x] certbot copy certificates for unique path -- [x] better error page -- [x] add favicon.ico + special path -- [x] [http.server security](https://docs.python.org/3/library/http.server.html#http-server-security) -- [x] launch separate upgrade 80->443 server when https -- [x] token management with "generate" command and bind path to specific token -- [x] docker compose example + .env -- [x] 404 GET on host not found -- [x] 403 PUT on host already taken -- [x] remove dot files after file extract -- [x] unit tests -- [x] github actions -- [x] X-Redirect -- [x] X-Proxy -- [ ] proper doc +* a main server exposing on port 80 (http) and port 443 (https) +* a weekly crontab for updating certificates -### Makefile targets - -```txt -Usage: make [target1] [target2] ... - -Commands/Targets: -help show this message -install install project -update update project dependencies -format format project -lint lint project -build build project -start start server in localhost -test test project -test-% test project with specific test -coverage test project with coverage -uv-sync uv sync -uv-upgrade uv sync upgrade -ruff ruff check -ruff-fix ruff check (and fix) -ruff-format ruff format -ruff-format-check ruff format (check only) -ty ty check -unittest unittest -unittest-% unittest -k [filter] -coverage-unittest coverage run -m unittest -coverage-report coverage report -coverage-html coverage html -coverage-xml coverage xml -docker-build docker build -docker-run docker run -``` +```bash +cp crontab.example crontab +cp compose.example.yml compose.yml +cp .env.example .env +$EDITOR .env # update HOST and TOKEN_SALT +docker compose up +# whenever you need a new token +docker compose run stapler token +``` \ No newline at end of file