July 26, 2026
Building Temporary File Sharing That Actually Expires
THE PAIN POINT
By Xudan
3 min read
THE PAIN POINT
Sharing a file or a block of code with your colleague is quite easy. You can use discord, slack ,whatsapp or other countless platform.
The challenge appears when sharing content with a person, whom you don't know personally , when you want to make it publicly accessible without requiring people to join a Discord server, create an account, or be added to a group.
The solution could be a link or a QR that anyone can access instantly but more importantly you want to make sure the content disappears after a certain period of the time.
Most file-sharing and messaging platforms are designed for persistence. Once something is uploaded, it often remains available indefinitely unless someone manually removes it. For developers sharing temporary configuration files, code snippets, logs, or troubleshooting data, that creates an unnecessary problem: the information outlives its usefulness.
What should be a quick, temporary exchange of information often becomes permanent storage.
DESIGNING THE SOLUTION (Copy Pasta)
Backend: Go REST API
The backend is written in Go, exposing a small REST API for creating and retrieving pastes/files. A few decisions that shaped it:
- Stateless API layer — all state (paste content, metadata, TTL) lives in Redis and file storage, not in the application process. This makes the API layer trivially horizontally scalable if needed later.
- Simple, predictable routes —
POST /api/v1/sharesto create,GET /api/v1/shares/:idto retrieve. No auth, no accounts, minimal surface area.
Go was also a personal choice — I wanted to get better at writing production-shaped Go outside of tutorials, and a small, well-scoped API service is a good way to do that.
4. Frontend: React
The frontend is a minimal React app with one job: make the interface disappear so the content is the focus. Core UI decisions:
- A single paste/upload form as the primary interaction — no onboarding, no account creation
- TTL selection (10 min / 1 hour / 24 hours / 7 days) as a first-class, visible control, not a buried setting
- QR code generation for quick device-to-device sharing, so a link doesn't have to be manually typed or copied across devices
The frontend is built as a static bundle and served independently from the API, which keeps the two deployable and scalable separately.
5. The Core Guarantee: TTL Expiration with Redis
This is the part of the project I'd point to first if someone asked "what did you actually engineer here?"
Redis has native key expiration — you set a TTL on a key, and Redis itself guarantees the key is gone (or inaccessible and reclaimed) once that TTL elapses. This isn't a cron job the application owns; it's a core engine feature enforced by Redis's own expiry cycle.
SET paste:abc123 "<content>" EX 600SET paste:abc123 "<content>" EX 600That single command replaces an entire homegrown cleanup subsystem — no scheduler to maintain, no "did the sweep job actually run" dashboard, no drift between what the database thinks is expired and what's actually been deleted.
The race condition worth knowing about: if paste/file metadata lives in Redis but the file content lives elsewhere (disk, object storage), you now have two systems that both need to expire in sync. If the metadata key expires while the underlying file write happened out of band, you can end up with orphaned file bytes with nothing pointing to them — or worse, a window where content is retrievable before its TTL key is even set.
The fix: make the TTL assignment and the content write atomic from the client's perspective. A paste/file isn't considered "live" until both operations succeed together; if either fails, neither is retrievable. Small detail, but it's the difference between TTL as a feature and TTL as a guarantee.
6. Secure Exposure: Cloudflare Tunnel
Separately from expiration is the question of how the server is exposed to the internet at all. The traditional approach — open an inbound port, point DNS at a public IP, manage TLS certs manually — works, but leaves the origin server directly reachable and responsible for defending itself.
A tunnel inverts this: the server makes an outbound connection to the tunnel provider's edge, and all inbound traffic routes through that edge instead of hitting the server's IP directly. I used Cloudflare Tunnel for this. Practical benefits:
- No inbound ports to open or firewall rules to maintain on the origin
- TLS termination handled at the edge
- DDoS mitigation happens before traffic reaches the origin at all
- The server's actual IP is never exposed publicly
For a small, single-operator project, this removes an entire category of infrastructure security that would otherwise need to be built and maintained by hand.
7. Deployment on AWS
The backend runs on AWS, with the Cloudflare Tunnel providing the path in from the public internet and Redis handling the data layer's expiration guarantee . This was the area with the steepest learning curve for the weekend — going from "works on localhost" to "works reliably once it leaves my machine" surfaced most of the real issues, particularly around environment configuration and cross-origin access between the frontend and API.
Checkout Copy Pasta : https://copy-pasta-cp.vercel.app/
8. Room For Improvement
What started as a simple paste-sharing tool quickly became a lesson in expiration semantics, object storage, infrastructure security, and deployment.
I will love to hear what i could have done better.
github: github.com/sudankdk