# 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) - [Publishing your site to your stapler server](#publishing-your-site-to-your-stapler-server) - [Sample github actions](#sample-github-actions) - [Redirecting hosts with DNS](#redirecting-hosts-with-dns) - [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] [--self-signed-path SELF_SIGNED_PATH] [--certbot | --no-certbot] [--certbot-conf CERTBOT_CONF] [--certbot-www CERTBOT_WWW] [--host HOST] [--http-port HTTP_PORT] [--https-port HTTPS_PORT] [--https | --no-https] [-t TOKEN_SALT] [--max-size-bytes MAX_SIZE] [-b BIND] COMMAND ... Static pages as simple as a gzip file positional arguments: COMMAND run Run Stapler server renew Renew certificates token Generate a new token options: -h, --help show this help message and exit --debug, --no-debug -d, --data-dir DATA_DIR directory where pages are/will be stored (default: ./data) --certificates, --no-certificates Handle certificates (default: true) --self-signed-path SELF_SIGNED_PATH Self-signed certificates dir (default: ./data/.certificates) --certbot, --no-certbot Use Certbot (default: true) --certbot-conf CERTBOT_CONF Certbot config dir (default: /etc/letsencrypt) --certbot-www CERTBOT_WWW Certbot www dir (default: ./data/.certbot) --host HOST server default host (default: localhost) --http-port HTTP_PORT server http port (default: 80) --https-port HTTPS_PORT server https port (default: 443) --https, --no-https Use https (implies --certificates) (default: true) -t, --token-salt TOKEN_SALT salt for tokens generation --max-size-bytes MAX_SIZE max size of accepted archives (in bytes) (default: 2000000) -b, --bind BIND server bind address (default: 0.0.0.0) (Each option can be supplied with equivalent environment variable.) ```
## HTTP API ### Create/update page from gzip ```txt PUT /{page}/ X-Token (your API token) X-Host (optional host as entrypoint) X-Host-Only (optional host as entrypoint) (body with tar data) ``` ```bash # 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/ # 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 and /my-project/ tar -czC dist . | curl -X PUT \ --data-binary @- \ -H 'X-Token: ' \ -H 'X-Host: myproject.example.com' \ https://stapler-host/my-project/ # make stapler server identifiers myproject.example.com only tar -czC dist . | curl -X PUT \ --data-binary @- \ -H 'X-Token: ' \ -H 'X-Host-Only: myproject.example.com' \ https://stapler-host/my-project/ ``` > [!NOTE] > Creating/updating comes with `X-Host` for enabling host-based resolving but you can also use `X-Host-Only` to do the same thing but disable listing as /path/. ### Create/update page with redirect ```txt PUT /{page}/ X-Token (your API token) X-Redirect (redirection target) X-Host (optional host as entrypoint) X-Host-Only (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) X-Host-Only (optional host as entrypoint) ``` ```bash # create /my-website/ that proxies to http://host.containers.internal:8000 curl -X PUT \ -H 'X-Token: ' \ -H 'X-Proxy: http://host.containers.internal:8000' \ https://stapler-host/my-project/ ``` ### Delete page ```txt DELETE /{page}/ X-Token (your API token) ``` ```bash # delete /my-project/ curl -X DELETE \ -H 'X-Token: ' \ https://stapler-host/my-project/ ``` ## Publishing your site to your stapler server * Create first your token * See [Create/update page from gzip](#createupdate-page-from-gzip) ### Sample github actions ```yaml deploy: name: Deploy needs: build runs-on: ubuntu-latest steps: - name: Download artifact uses: actions/download-artifact@v8 with: name: production-files path: ./dist - name: Create archive run: tar -czC dist -f dist.tar.gz . - name: Deploy to Stapler server run: curl -X PUT -H 'X-Token: ${{ secrets.STAPLER_TOKEN }}' -H 'X-Host: ${{ vars.TARGET_HOST }}' --data-binary "@dist.tar.gz" https://stapler-host/my-project/ ``` ### Redirecting hosts with DNS **Root host** (e.g. `example.com`) | name | type | value | | - | - | - | | `@` | `A` | (server ipv4) | | `@` | `AAAA` | (server ipv6) | **Subdomain** (e.g. `www.example.com`) | name | type | value | | - | - | - | | `(subdomain)` | `CNAME` | (server host). | ## Docker Stapler ships with a deploy-ready `Dockerfile` and a sample `docker compose` stack with: * a main server exposing on port 80 (http) and port 443 (https) * a weekly crontab for updating certificates ```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 --rm stapler token ```