Sending a large file to someone usually means uploading it to a service, getting a link and sharing it. After a few days the file is gone. This article shows how to build such a service yourself: one program called DocTunnel, written in Wantzel, a strict procedural language that compiles to a single Linux executable. The compiler is a free download.
Why build it yourself? You decide where the files live, how long they stay and who can reach them. And on the way you touch every layer of a web service, from parsing a request to keeping a server running.
The Architecture
The program never faces the internet directly. Caddy, a reverse proxy, handles HTTPS and passes requests to DocTunnel on the server itself. Each upload gets its own folder on disk, a sweeper removes expired uploads, and systemd keeps the program running.
The Steps in Short
- A server that answers. Route requests by path: the home page, the upload endpoint and the share link
/p/<code>. - Upload without filling memory. The browser sends a multipart request. The server writes it to disk block by block while it arrives, so a 10 GB file needs no more memory than a small one.
- Links nobody can guess. The code in the link comes from the operating system's random source.
- Expiry and cleanup. The sender picks how many days to keep the files. A sweeper deletes what has run out.
- Security. File names from the browser are cleaned, passwords are stored as a salted hash, and wrong guesses are limited.
- Deployment. A small VPS with SSH keys, Caddy in front for HTTPS, and a systemd unit that restarts the program after a crash.
Here is the first step, the server with its three routes:
import http; var st: int; procedure app.request; begin st := 200; if http.pathis("/") then http.add("hello from your own transfer service\n") else if http.pathis("/upload") and (http.method <> 1) then http.add("upload: nothing stored yet\n") else if http.pathstarts("/p/") then begin http.add("code: "); http.addb(http.inbuf, http.pathat + 3, http.pathlen - 3); end else begin st := 404; http.add("not found\n"); end; http.finish(st, "text/plain"); end; begin http.serve(8553, 1); end. And the code that makes a link safe to share. It reads 24 random bytes and maps each one to an alphabet of 32 characters without look-alikes such as l and 1:
import io; const AB = "abcdefghijkmnpqrstuvwxyz23456789"; var r: array[0..23] of char; fd, i: int; begin fd := sys3(2, sadr("/dev/urandom\x00"), 0, 0); if fd < 0 then io.fatal("no random source"); if io.read(fd, addr(r[0]), 24) <> 24 then io.fatal("short read"); for i := 0 to 23 do r[i] := schar(AB, band(ord(r[i]), 31)); sys1(3, fd); io.out(STDOUT, addr(r[0]), 24); io.puts(STDOUT, "\n"); end. Output (different on every run):
mvw3w8ftjvs5fpgwfrgpbjmd Since 32 is a power of two, band(byte, 31) keeps 5 bits of each byte and every character is equally likely.
The Result
Uploading a 10 GB video file:
After the upload the sender gets two links: one to share, and a private one to see the downloads or delete the upload:
The receiver opens the share link and downloads the file:
What You Learn
Building a file sharing service teaches how uploads travel over HTTP and why streaming matters for large files. It shows what makes a secret link secret, and what it takes to run a program on a server you look after yourself. Near the end, the course adds an AI assistant that checks the server over SSH and asks before it changes anything.
The full step-by-step video series builds DocTunnel in 50 short lessons, each with its source files.
Based on my own video course; drafted with AI assistance from my course material.



