Meet S.O.C.K.S.
Author: Andrew Porter
Published: 10/4/2026
-
Serve what you need today, extend it for whatever comes tomorrow - without having to reinvent the wheel every single time.
The Issue
Every project eventually needs something to serve a folder of files - it could be a docs site, a device’s firmware updates, or any of the other millions of kinds of build system outputs.
Our Take
The usual answer is to copy the last Express boilerplate you copied from the last Express boilerplate you copied from a starter tutorial… 10 years ago. Once you’ve managed to dig up the source code and stale harness you’re left to hope it still has sane defaults for whatever you’re working on today - but that’s just not a great system, if we’re being honest with ourselves as engineers. This endless cycle ends up being a throwaway task so offputting that we also tend to ignore any investment in the resulting infrastructure, compounding the issues next time you do the copy/paste dance for a fresh project. We got tired of constantly rebuilding that foundation and all of the support tooling, and we’re sure you are too - so today we’re announcing our solution to those issues: the Static-Origin-Content-Kwik-Serve Server. It’s Open Source, it’s on our GitHub, it’s up-to-date, and it does one job really well.
What is SOCKS?
SOCKS is a “hyper-modern” NodeJS & Express static content server written in TypeScript, with just one job - you point it at a directory and it serves the files. Hyper-modern means we make sure it’s constantly up to date and functional - no stale dependencies, no old framework versions updated once every few years, just small incremental maintenance for a piece of core infrastructure that we rely on every day. Basic security headers, rate limiting, and a health check are included, so you don’t have to remember to add them. You can run it straight from the terminal or as a batteries-included container for cloud workloads, built on-demand or pulled from a central registry. Serve what you need today and extend it for whatever you need tomorrow - it’s a production-ready base, not a framework you have to work around.
Why We Built It
This is the “hard delivery” angle. We ship connected devices and cloud services, and nearly all of them need to serve static content somewhere, such as a firmware portal, a docs page, or a dashboard shell. Each time, the same detail thorns turn up: shifting Express or dependency APIs, the missing header configuration, the rate-limit implementation headaches, the container that runs as root, and worst of all - npx serve when it’s late and we’re desperate. We wanted a clean, maintainable version where the basic hardening is built in from first commit and not bolted on after launch. That’s the zero-trust, secure-by-default approach we take, applied to a very boring problem.
The Stack
No funny business, here - just the latest: Alpine images, Node LTS runtime, Express framework, written in one single TypeScript file, and with only four small additional runtime dependencies (compression, express-rate-limit, helmet, ms). The README tracks every stack version in a table and we ship a CICD script that displays the live version of every single part of the stack, so there’s never any question about what versions you’re running in production.
Maintained and Tested, Seriously
The hard business for a project like this doesn’t come from complexity of the codebase, but from shifting runtime structures, framework API changes, and dependency updates - then validating that an updated server still works as expected and that there aren’t any unknown-unknowns that have blown a hole in your security posture. This is a tale as old as time in Software Engineering and we wanted a different approach for ourselves, at 315Concepts - so we built exactly what we were looking for! The repo ships a full smoke test (npm run smoke) that runs the built image, locked down just like in production. It then checks the behaviors the README promises: headers, paths, logging, shutdown, proxy handling, and basic attack surfaces. When it’s time to make changes npm run versions prints the exact stack versions, so a release check is just one line: npm run build && npm run smoke && npm run versions. The outcome is a straightforward maintenance process that can quickly and easily prove that the README is behaviorally validated, not just written to sound good.
Honest Limitations
We’re dedicated to talking about some of the soft underbelly of our creations - and even though we think this project is pretty well put together, there’s still a few points to consider with SOCKS:
- The rate-limit counter lives in memory, per process - not a problem for a single server instance but if you need fleet-wide rate limits, cross-restart limit consistency, or other advanced rate-limiting features you will have to build them yourself
- Symlinks are followed, including ones that point outside the served directory - this behaviour is usually discouraged but with SOCKS it’s an intentional design choice because what goes in the directory is the operator’s call. Do not point SOCKS at a directory that you don’t control or have the ability to check for symlinks in.
- HSTS is configured in code, not through an env var - it can blow a 30-day sized hole in your domain for clients using mixed security schemes. If your clients are browser based and you’re serving mixed HTTP/HTTPS content (or plan to) please read more about the implications of having an HSTS-enabled server as part of your architecture.
- Doing it - publishing a maintained project means you’re in the funnel the moment you hit “push.” We uploaded the NodeJS 24 version we’d been running internally, switched on dependabot, and almost immediately got hit with the LTS upgrade to v26. That’s the shifting-runtime treadmill from the section above, showing up before the ink on the README was dry. SOCKS is built to make that churn cheap to deal with, because the version table,
npm run versions, and the smoke test are all there to answer “did the upgrade break anything?” in one line. But it is not zero effort. If you fork or extend SOCKS, plan on owning your own upgrade cadence, and expect the runtime, the framework, and the dependencies to keep moving whether or not your project does.
Get It / What’s Next
SOCKS is available, now, on our GitHub. Clone it and you’re serving files in just three commands:
npm install
npm run compile
STATIC_DIR=./public PORT=8080 node dist/index.js
If you’re running containerized workloads the README also covers running SOCKS via Docker Compose and plain-old-Docker-container, plus a Traefik setup guide for running it behind a compact cloud-native proxy.
This is the same deal we promised in the intro: the code is out in the open so you can use it, break it, and improve it. If you hit a rough edge, find a gap in the smoke test, or want SOCKS to do something it doesn’t yet - open an Issue or send a Pull Request. The best fixes tend to come from someone else’s “oh, that’s why nobody does it that way” moment - so help us help you, by helping us.
And yes, Socks the cat is in the README, but don’t worry - she likes small containers but we didn’t have her write any of the code for this project.
