A patched build of fiche, the command-line TCP pastebin - Now with selfservice paste delete support!
436
A patched, production-ready Docker image of fiche/termbin, the minimal TCP pastebin (cat file | nc domain 9999).
This fork fixes four silent bugs present in the upstream C source and adds slug deletion support.
cat file | nc your.domain 9999
# → https://your.domain/a3f9b2c1d4e5f6a7
The recommended setup runs two containers:
git clone https://github.com/Leproide/termbin-reborn
.env# Public domain returned in URLs
FICHE_DOMAIN=your.domain
# TCP port for uploads
FICHE_PORT=9999
# fiche flags (see below for reference)
FICHE_ARGS=-S -s 16 -B 10485760 -l /data/log/fiche.log -P 9998
# TCP port for delete requests
FICHE_DELETE_PORT=9998
# nginx internal port (loopback only — put a reverse proxy in front)
NGINX_PORT=62365
index.html in the repo root is served at https://your.domain/ by nginx. Edit it to add a description, usage instructions, or branding for your instance. It is mounted as a read-only bind mount and takes effect without rebuilding the image:
volumes:
- "./index.html:/srv/static/index.html:ro"
docker compose up -d
docker-compose.yml doesservices:
# fiche: TCP pastebin
fiche:
image: leprechaunit/fiche:latest
container_name: fiche
restart: unless-stopped
ports:
- "${FICHE_PORT:-9999}:9999" # upload
- "${FICHE_DELETE_PORT:-9998}:9998" # delete: echo -e "slug\ntoken" | nc domain 9998
environment:
FICHE_DOMAIN: ${FICHE_DOMAIN}
FICHE_ARGS: ${FICHE_ARGS}
volumes:
- "./data/paste:/data/paste"
- "./data/log:/data/log"
# termbin-web: nginx static file server
termbin-web:
image: nginx:alpine
container_name: termbin-web
restart: unless-stopped
ports:
- "127.0.0.1:${NGINX_PORT:-62365}:80"
volumes:
- "./data/paste:/srv/paste:ro"
- "./nginx.conf:/etc/nginx/nginx.conf:ro"
- "./index.html:/srv/static/index.html:ro"
The two containers share ./data/paste — fiche writes, nginx reads. The nginx port is bound to 127.0.0.1 only; a reverse proxy (Caddy, nginx, Apache…) on the host should front it and terminate TLS.
| Variable | Default | Description |
|---|---|---|
FICHE_DOMAIN | (required) | Public hostname returned in uploaded URLs |
FICHE_PORT | 9999 | Host port mapped to the upload listener |
FICHE_DELETE_PORT | 9998 | Host port mapped to the delete listener |
FICHE_ARGS | (none) | Extra flags passed directly to fiche (see below) |
NGINX_PORT | 62365 | Internal nginx port, bound to 127.0.0.1 |
FICHE_ARGS reference| Flag | Description |
|---|---|
-S | Return https:// links instead of http:// |
-s <n> | Slug length (default: 4) |
-B <bytes> | Max upload size in bytes (default: 32768; 10 MB = 10485760) |
-l <path> | Log file path inside the container |
-L <addr> | Listen address (default: 0.0.0.0) |
-p <port> | Listen port (default: 9999) |
-u <user> | Drop privileges to this user after bind |
-P <port> | Delete service port (0 = disabled) |
When -P <port> is set, every upload returns both the paste URL and a ready-to-run delete command:
$ cat file.txt | nc your.domain 9999
https://your.domain/a3f9b2c1d4e5f6a7
To delete this paste:
echo -e "a3f9b2c1d4e5f6a7\\n<token>" | nc your.domain 9998
Copy and run that line to permanently remove the paste. The token is generated once at upload time and stored server-side, there is no way to retrieve it afterwards, so save the delete command if you need it later.
| Container path | Purpose |
|---|---|
/data/paste | Slug directories (shared with nginx) |
/data/log | fiche log file |
Mount both with bind mounts so data survives container restarts:
volumes:
- "./data/paste:/data/paste"
- "./data/log:/data/log"
| Port | Protocol | Purpose |
|---|---|---|
9999 | TCP | Upload |
9998 | TCP | Delete |
-B valuesThe receive buffer was a VLA on the thread stack. Any -B value larger than the default 32 KB caused an immediate silent stack overflow: the thread died, no URL was returned, no file was saved.
Fix: heap allocation via malloc, grown dynamically per connection.
MSG_WAITALL combined with SO_RCVTIMEO caused recv to return ≤ 0 when the client sent fewer bytes than buffer_len and closed the connection — the normal case for cat file | nc. All data was discarded silently.
Fix: replaced with a read loop that accumulates data until EOF or the buffer limit is reached.
The original approach called calloc(buffer_len) for every connection regardless of upload size. A 5-byte paste with -B 10485760 would allocate and hold 10 MB per thread.
Fix: buffer starts at 64 KB and grows via realloc only as needed up to -B. malloc_trim(0) is called after each connection to return freed heap memory to the OS immediately.
free(c) was called before close(c->socket), reading a freed struct field — undefined behaviour flagged by -Wuse-after-free.
Fix: reordered cleanup so the socket is closed before the struct is freed.
Content type
Image
Digest
sha256:759202080…
Size
26.9 MB
Last updated
3 days ago
docker pull leprechaunit/fiche