Two small, independent file-sharing services for handing files to friends in mainland China from a Shenzhen ECS box — a browsable folder, and expiring links with an admin UI. Each is its own Docker Compose service with no shared database or cloud dependency.
Deliberately reachable by bare IP, not a domain — mainland China requires ICP filing for anything served at a domain name, and a bare IP sidesteps that entirely.
The pages you log in to. These are the current addresses — they change if a box's public IP changes, so if one stops answering, check the IP first (see the IP Change Checklist under Docs).
| Box | App | Start here |
|---|---|---|
| Shenzhen | fileshare management (upload, folders, passwords, expiry) |
http://47.107.139.170:8080/admin |
| Shenzhen | gokapi admin |
http://47.107.139.170:9001/admin |
| Singapore | gokapi admin |
http://singapore.1000600.xyz:9001/admin |
- Usernames and passwords are not in this repo. They are in the gitignored
.envat the root of the local clone, next to these same addresses (SZ_FILESHARE_UPLOAD_URL,SZ_GOKAPI_URL,SG_GOKAPI_URL) — update both places when an IP changes. fileshare's management page lives at/admin. Its old address,/upload, still forwards there. Folder listings carry no link to it, so the address has to be typed or bookmarked.- The Shenzhen addresses use the bare IP on purpose (no ICP filing). The Singapore one uses a hostname, which is re-pointed automatically when that box's IP changes.
- The bare addresses without
/adminare not the way in::8080/shows visitors nothing, and:9001/redirects to Gokapi's GitHub page.
| App | Port | What it's for | Source |
|---|---|---|---|
fileshare/ |
8080 | Browsable folders — the top level is not listed for visitors, so someone can only open a folder or file whose exact link they were given (and everything inside that folder), and an optional shared viewing password (VIEW_PASS) can be required before anything opens; each row has a copy-direct-link button, a QR code button and, for files, a download button; clicking a name opens the file in the browser — plus a password-gated management page (upload / rename / delete / copy-link). Image files show a thumbnail and open in an in-page viewer where you flip through the folder's images with the on-screen arrows, the arrow keys or a swipe (also on the management page). Layout adapts from phones up to 1120px wide |
Custom Python (stdlib only) |
gokapi/ |
9001 | Expiring links with a real admin UI, encrypted at rest | Gokapi |
fileshare replaced Filebrowser, then Alist — Filebrowser archives 2026-09-01 with no further releases, and Alist ended up being more than this needed. gokapi was added afterward to cover one-off private links with real expiry, a role a since-removed companion app (quickshare-sz) used to fill.
Gokapi's bare address redirects away on purpose. Opening http://<host>:9001/ sends you to Gokapi's GitHub page — it has no public home page, and its RedirectUrl setting (in gokapi/config/config.json on the box) is still the default. That is not a fault. The admin login is at http://<host>:9001/admin; shared files use their own download links.
Use fileshare to share a collection with people you trust, and Gokapi to send one specific file to one person.
fileshare |
gokapi |
|
|---|---|---|
| Best for | A folder of things to browse: screenshots, trip documents, anything a friend picks from | One file for one person |
| The link | One link per folder, which stays valid as you add files | One unguessable link per file |
| Viewing | Images and PDFs open in the browser, with thumbnails | A download page per file |
| Access control | Shared or per-folder password; anyone with a folder's link and password sees everything in it | Optional password per file |
| Expiry | Optional, per top-level folder, by days | Per file, by days or by number of downloads |
| On the server | Stored as plain files | Encrypted at rest |
| Tracking | None | Download count per file |
| Size limit | 500MB per upload | Far larger (set to 100GB) |
Rule of thumb: if you would be uncomfortable with a stranger seeing it, use Gokapi; if it is just convenient to have in one place, use fileshare. Passport scans, visa paperwork and contracts belong in Gokapi with an expiry.
Caveat for both: neither uses HTTPS, so files and passwords travel unencrypted between the box and the visitor. Gokapi's encryption only protects files while stored. For anything truly confidential, zip it with a password first and send that password by a different channel.
Each app directory is self-contained:
cd fileshare # or gokapi
cp .env.example .env # fileshare only — edit in real values
docker compose up -d --buildgokapi doesn't use .env — its admin account is created on first boot via its own /setup wizard in the browser, not environment variables. Its default docker-compose.yml pulls the upstream f0rc3/gokapi image directly; if that registry is blocked on your network (see below), use docker-compose.china.yml instead.
Official images (python:3.12-alpine, alpine:latest) pull fine through China-side Docker registry mirrors. Third-party namespaced images — like f0rc3/gokapi — get a 403 from the docker.m.daocloud.io mirror, and the once-common hub-mirror.c.163.com mirror is dead (its hostname doesn't even resolve anymore). GitHub's release-asset CDN (release-assets.githubusercontent.com) is also unreachable directly from mainland China.
The workaround, wired up as gokapi/docker-compose.china.yml:
- On a machine with normal internet access — not the target server — run
gokapi/fetch-binary.shto download the Gokapi release binary. scpthe resultinggokapi/bin/directory to the server.docker compose -f docker-compose.china.yml up -d --build— this builds a thin local image wrapping the binary instead of pulling a prebuilt one.
The Shenzhen deployment serves a mainland Chinese audience, so its public download/password pages are translated to Simplified Chinese via gokapi/custom/public.js — Gokapi's supported no-rebuild customization hook (it auto-loads any custom/public.js it finds, mounted at /app/custom in docker-compose.china.yml). Its PublicName config value is also set to 深圳文件快传 instead of an English name. This is scoped to that one deployment on purpose — other boxes running this repo keep the English UI unless you copy custom/public.js over and mount it the same way.
Gokapi caches custom/public.js for 2 days, so after editing it on the server, bump custom/version.txt (a plain integer, e.g. echo 2 > version.txt) and restart the container — this changes the script's URL and forces every client to fetch the new version instead of a stale cached copy.
Gokapi's admin page only has a per-file delete button. gokapi/clear-all.sh clears a whole box in one go through Gokapi's API — run it from your Mac, from the repo root:
bash gokapi/clear-all.sh sg # Singapore box
bash gokapi/clear-all.sh sz # Shenzhen box
bash gokapi/clear-all.sh sg -y # skip the confirmation questionIt lists every stored file, asks you to type yes, deletes them all (every share link stops working — there is no undo), then reports how many are left. It reads SG_GOKAPI_URL + SG_GOKAPI_API_KEY (or the SZ_ pair) from the gitignored .env at the repo root; create the key in the admin page's API Keys menu with permission to view and delete files. Requires curl and jq.
Four reference pages, published as standalone HTML (also mirrored in docs/ here — English only, whichever README you're reading):
- File Share Cheat Sheet — the original quick-reference for fileshare
- IP Change Checklist — what to do within a minute of the server's IP changing
- Where Your Files Live — storage paths, add/remove commands, and retention per app
- New Box, Same Stack — replicating both apps onto a fresh Ubuntu box
- Every credential in this repo's compose files is a placeholder read from a gitignored
.env— real values never enter git history. The master copy of every password (fileshare's upload login and both boxes' Gokapi admin logins) is the gitignored.envat the root of the local clone on Alan's Mac. A forgotten Gokapi admin password can't be read back from the box (only a hash is stored) — reset it withgokapi --deployment-password <new>while the container is stopped, then save the new value in that.env. One exception as currently deployed: on the Shenzhen box,fileshare's compose file has its username and password written in directly rather than read from a.env— that edited copy exists only on the box, not in this repo. gokapi's data directory is encrypted at rest (Level 1 — local key, so the container still restarts unattended after a crash or reboot without manual intervention).fileshareviewing passwords:VIEW_PASS(optional) is one shared password for the whole site, and each top-level folder can have its own password, set on the management page, which replaces the shared one for that folder. Entering one sets a 30-day cookie for that scope; changing a password signs out everyone who used it. After 5 wrong tries from one address (viewing or admin), that address is refused for 10 minutes. Passwords still travel over plain HTTP and folder passwords are stored as plain text on the box, so this keeps out casual visitors and scanners rather than a determined attacker.fileshareQR codes are the link itself drawn as a picture, generated in the viewer's own browser by a vendored copy of qrcode-generator (MIT,fileshare/qrcode.min.js). There is no redirect or short link, and the link is never sent to an outside service. A code carries only the address, so the folder's password is still asked for.filesharenever serves dot-files, never overwrites on upload (a seconda.pdfis saved asa (1).pdf), and refuses a rename or new folder that would collide with an existing name.filesharefolder expiry: a top-level folder can be given a number of days on the management page; when the time is up the folder and everything in it is deleted automatically, with no undo.filesharestores files unencrypted, as plain filesystem paths — access control is entirely "does the link/password, whichever the app uses."