From 43f1168d6a11f60fee27c487d12ca52d997a489f Mon Sep 17 00:00:00 2001 From: Jokin Date: Tue, 14 Jul 2026 15:59:05 +0200 Subject: [PATCH] Add landing page + Caddy download host (site/) Self-contained, no-JS landing page (tinygrad-minimal) that doubles as the artifact download host, served by Caddy on an internal :80 box. - site/index.html: static page, "Same tool, only a little different", feature highlights (remote->remote, symmetric panels, ssh_config awareness, edit-in- place, self-copy guard, ...), fixed stable download links, FAQ (unsigned notes). - site/Caddyfile: one flat /dl/ folder with browse + range requests and per-type Cache-Control (patches immutable, update.json no-cache, installers short). - site/deploy.sh: drop a build's artifacts/stable-* into /dl/ (renames the win portable zip to a stable name). - Flat folder matches electrobun's artifacts/ layout, so it's also the future updater baseUrl; per-build folders/symlink dropped in favor of it. - docs/build-and-release.md: document the download host + deploy flow. Verified: caddy validate + live smoke test (links, cache headers, 206 range, 404 fallback, deploy.sh copy/rename) against a temp root. Co-Authored-By: Claude --- docs/build-and-release.md | 25 +++++++ site/Caddyfile | 34 +++++++++ site/README.md | 69 ++++++++++++++++++ site/assets/README.md | 11 +++ site/deploy.sh | 37 ++++++++++ site/index.html | 149 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 325 insertions(+) create mode 100644 site/Caddyfile create mode 100644 site/README.md create mode 100644 site/assets/README.md create mode 100755 site/deploy.sh create mode 100644 site/index.html diff --git a/docs/build-and-release.md b/docs/build-and-release.md index 5b02a80..ecb6df4 100644 --- a/docs/build-and-release.md +++ b/docs/build-and-release.md @@ -67,6 +67,31 @@ runner matrix, each running the same release script; inert until act_runners with those labels are registered. Needs `fetch-depth: 0` (the build number is the commit count). Runner prereqs are commented in the workflow file. +## Download host (`site/` + Caddy) + +`site/` is a self-contained landing page **and** download host, served by Caddy on an +internal box (plain HTTP `:80`, no domain/TLS). Deploys to `/srv/miniscp/`. + +- `site/index.html` — pure static, no JS, tinygrad-minimal. Download buttons link to **fixed + stable filenames** (`/dl/stable-macos-arm64-miniSCP.dmg`, …) so the page never changes per + release. Logo/screenshot `` slots are commented in, images live in `site/assets/`. +- `site/Caddyfile` — one flat `/dl/*` folder with `file_server browse` + range requests, and + per-type `Cache-Control`: `*.patch` immutable (unique hashed names), `*update.json` `no-cache` + (updater must see new versions), installers (`*.dmg *.zip *.tar.zst`) `max-age=300` (stable + names overwritten each release). Landing page has **no** SPA fallback → unknown paths 404. + Path matcher gotcha: use suffix globs like `*update.json`, not `*/*update.json`. +- **One flat folder, no per-build dirs** — this layout IS electrobun's `artifacts/` feed, so it + doubles as the (future) updater `baseUrl`. Publishing = drop this machine's `artifacts/stable-*` + into `/dl/`; installers overwrite in place, `.patch` files accumulate (never delete them, or + older installs lose their incremental-update trail). **Tradeoff:** only the latest full + installer is downloadable; old full versions are overwritten. +- `site/deploy.sh` — run per build machine after `scripts/release.ts`; copies `artifacts/stable-*` + and renames the build-numbered win portable zip to the stable `stable-win-x64-miniSCP-portable.zip`. + `MINISCP_DL_DIR` overrides the target (stage locally, then rsync to the server). +- **Future updater** (not wired yet): set `release.baseUrl = http:///dl/` in + `electrobun.config.ts` (currently unset) → builds start emitting `.patch` files that `deploy.sh` + already ships. Then call the electrobun `Updater` API on launch/interval/tray. + ## Icons `scripts/gen-icons.ts` (resvg, dev-time): renders `assets/logo.svg` into the diff --git a/site/Caddyfile b/site/Caddyfile new file mode 100644 index 0000000..c1c2e07 --- /dev/null +++ b/site/Caddyfile @@ -0,0 +1,34 @@ +# miniSCP landing page + artifact host. +# Local / internal, plain HTTP on :80 (no domain, no TLS). +# Deploy target is /srv/miniscp — see site/README.md. + +:80 { + root * /srv/miniscp + encode zstd gzip + + # Flat artifact feed: these files are BOTH the human downloads AND (later) the + # electrobun updater baseUrl. Publishing a build = drop its artifacts/ files here; + # stable-named installers overwrite in place, hashed .patch files accumulate. + handle /dl/* { + # Incremental update patches have unique hashed names → cache forever. + @patch path *.patch + header @patch Cache-Control "public, max-age=31536000, immutable" + + # The updater feed must always reflect the newest published version. + @feed path *update.json + header @feed Cache-Control "no-cache" + + # Installers/payloads keep stable names but get overwritten each release. + @pkg path *.dmg *.zip *.tar.zst + header @pkg Cache-Control "public, max-age=300" + + # browse => directory listing; file_server serves range requests + # (resumable large .dmg downloads) by default. + file_server browse + } + + # Static landing page + assets. No SPA index fallback: unknown paths 404. + handle { + file_server + } +} diff --git a/site/README.md b/site/README.md new file mode 100644 index 0000000..ae1e93d --- /dev/null +++ b/site/README.md @@ -0,0 +1,69 @@ +# miniSCP site + +The all-in-one landing page **and** download host for miniSCP. One static page, one flat +download folder, served by [Caddy](https://caddyserver.com). No JS, no build step. + +## Layout + +``` +site/ + index.html # the landing page (pure static HTML/CSS) + Caddyfile # local :80 server config + deploy.sh # copy a build's artifacts into the download folder + assets/ # images (logo, screenshots) — dropped in as they're ready +``` + +Deploys to `/srv/miniscp` on the server: + +``` +/srv/miniscp/ + index.html + assets/ + dl/ # flat folder of all artifacts (the downloads + future updater feed) +``` + +## Run it + +```bash +# from the repo root, on the server +sudo mkdir -p /srv/miniscp/dl +sudo cp site/index.html /srv/miniscp/ +sudo cp -r site/assets /srv/miniscp/ # once assets exist + +caddy run --config site/Caddyfile --adapter caddyfile +# or install as a service: sudo caddy start --config site/Caddyfile +``` + +Then open `http:///`. + +## Publish a build + +electrobun can't cross-compile, so each OS/arch is built on its own machine. On each build +machine, after producing artifacts, drop them into the shared `dl/` folder: + +```bash +bun scripts/release.ts # or --target mac-x64 / win-x64 +site/deploy.sh # -> /srv/miniscp/dl +``` + +Serving on a different box than you build on? Stage locally, then sync: + +```bash +MINISCP_DL_DIR=./_dl site/deploy.sh +rsync -av ./_dl/ user@host:/srv/miniscp/dl/ +``` + +That's the whole workflow: **build, drop the artifacts, done.** Installers keep stable names and +overwrite in place, so the download links on the page never change. + +> **Don't delete old `*.patch` files.** They're the incremental-update trail for the (upcoming) +> built-in updater — removing them forces older installs to re-download the full app. + +## Notes + +- Downloads live under `/dl/` and are browsable at `http:///dl/`. +- The page links to fixed, stable filenames (`stable-macos-arm64-miniSCP.dmg`, …) so it stays + static and always points at the latest build. +- Builds are currently unsigned — the FAQ on the page covers the macOS `xattr` step and the + Windows SmartScreen prompt. +- `/dl/` is also the intended `release.baseUrl` for the future electrobun auto-updater. diff --git a/site/assets/README.md b/site/assets/README.md new file mode 100644 index 0000000..4f11185 --- /dev/null +++ b/site/assets/README.md @@ -0,0 +1,11 @@ +# Image assets + +Drop images here as they're ready; the page references them by relative path. + +Planned slots (commented into `../index.html`): + +- `logo.svg` — hero logo above the wordmark (`.logo`, 128×128). Source lives at repo + `assets/logo.svg`. +- `screenshot.png` — product shot under the intro paragraphs (`.shot`). + +To wire one up, uncomment the matching `` in `index.html`. diff --git a/site/deploy.sh b/site/deploy.sh new file mode 100755 index 0000000..2c962c7 --- /dev/null +++ b/site/deploy.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail +# Publish this machine's built artifacts into the served flat download folder. +# +# Run from the repo root AFTER building for this host's target, e.g.: +# bun scripts/release.ts # or --target mac-x64 / win-x64 +# site/deploy.sh +# +# electrobun cannot cross-compile, so each OS/arch is built (and deployed) on its +# own machine; every run just adds/overwrites that target's files in one flat dir. +# Installers keep stable names (overwrite in place); .patch files accumulate — never +# delete old ones, or users on older versions lose their incremental update trail. +# +# Serving locally? Leave MINISCP_DL_DIR unset (defaults to /srv/miniscp/dl). +# Serving on a remote box? Point MINISCP_DL_DIR at a local staging dir, then rsync: +# MINISCP_DL_DIR=./_dl site/deploy.sh +# rsync -av ./_dl/ user@host:/srv/miniscp/dl/ + +dl="${MINISCP_DL_DIR:-/srv/miniscp/dl}" +mkdir -p "$dl" + +# electrobun's flat artifacts (stable---*): installers, update payloads, +# update.json, and (once release.baseUrl is set) .patch files. +if compgen -G 'artifacts/stable-*' >/dev/null; then + cp -f artifacts/stable-* "$dl"/ +else + echo "deploy: WARN — no artifacts/stable-* found (did scripts/release.ts run?)" >&2 +fi + +# Windows portable zip is a release.ts extra (build-numbered) → give it a stable name. +port=$(ls -1 release/win-x64/*-win-x64-portable.zip 2>/dev/null | head -n1 || true) +if [ -n "$port" ]; then + cp -f "$port" "$dl/stable-win-x64-miniSCP-portable.zip" +fi + +echo "Published to $dl:" +ls -1 "$dl" diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000..3bd67ca --- /dev/null +++ b/site/index.html @@ -0,0 +1,149 @@ + + + + + + miniSCP: a dual-pane SFTP file manager + + + +
+ +

miniSCP

+

A dual-pane SFTP file manager.
Same tool, only a little different.

+ +
+ +
+

Same tool, only a little different

+

If you've ever used a two-pane file manager to move files over SFTP, you already know how to + use miniSCP. Two panels, a connection on each side, copy between them. Nothing to relearn.

+ +

The difference is in the corners. Both panels are fully symmetric — either side can be + your local disk or any saved server — so a copy isn't only up or down. You can move files + straight from one server to another, remote to remote, without staging them on your + machine first.

+ +

It's the same familiar tool, sanded down where the old ones snag.

+ + + +

What's different:

+ +

Remote → remote. Copy straight between two servers — nothing + staged on your machine.

+

Symmetric panels. Either side is your local disk or any saved server. Every + panel is equal.

+

Knows your servers already. Reads the hosts from your + ~/.ssh/config, and imports the saved sessions from your previous client.

+

Tabs that keep working. Open several sessions at once; transfers keep + running in background tabs.

+

Edit in place. Open a remote file in your editor — every save uploads + itself, automatically, until you disconnect.

+

Won't eat your files. A multi-layer guard catches when the source and + destination are secretly the same file, even behind NAT or split-DNS, before it can truncate + anything.

+

Honest overwrites. Compares size and date, tells you which copy is newer, + and lets you replace-all or skip-all in one go.

+

A queue with an ETA. Per-file speed and estimate, cancel anytime.

+

Permissions. Rename, delete, create folders and files, and change + permissions (chmod) on remote files.

+

Themes. Light, dark, or follow the system — with a set of accent + tones.

+

macOS and Windows. macOS is the primary target; Windows 11+ (x64) is in + beta.

+ +
+

Download

+

Always the latest stable build.

+ +

Looking for everything? browse all files.

+ +
+

FAQ

+
+
Which platforms are supported?
+
macOS (Apple Silicon and Intel) and Windows 11+ (x64). macOS is the primary target; + Windows is currently in beta.
+ +
macOS says the app is "damaged and can't be opened".
+
The builds aren't code-signed yet, so macOS quarantines them on download. Clear the + quarantine flag once and it opens normally: +
xattr -cr /Applications/miniSCP.app
+ +
Windows warns me with a blue SmartScreen box.
+
The Windows builds aren't signed yet either, so SmartScreen flags them on first run. Choose + "More info" → "Run anyway". The installer unpacks to your local app data; the portable + zip runs from anywhere.
+ +
Can I bring my existing servers over?
+
Yes. miniSCP reads the hosts from your ~/.ssh/config automatically, and it can + import the saved sessions exported from your previous file-transfer client.
+ +
Installer or portable on Windows?
+
The installer sets miniSCP up in your user profile with a desktop shortcut. The portable zip + is just the app — unzip it anywhere and run it, no install.
+
+ +