Summary
Right now the only documented way to run an app is per-folder npm install && npm run dev, and the only documented production path is AWS Amplify (amplify.yml + customHttp.yml at the repo root).
There is no container image, no compose file, and no nginx/Caddy config anywhere in the repo — I walked the full file tree on main (34,886 paths) and found zero matches for Dockerfile, docker-compose, compose.yml or nginx.
That makes self-hosting impractical. Someone who wants these apps on their own VPS/NAS/home lab currently has to clone the repo, install Node 22.12+, run a build in each of the 51 app folders, and then hand-write a static file server that reproduces the caching behaviour the apps actually depend on.
What would make self-hosting work
- A
Dockerfileper app (or one parameterizedDockerfileplus a build arg) that:- builds in
node:22(README requires >= 22.12), - runs
npm ci && npm run build, - serves
dist/from a multi-stage nginx or Caddy runtime image, - runs non-root and declares a
HEALTHCHECK.
- builds in
- A
docker-compose.ymlat the repo root that brings up a chosen set of apps behind one reverse proxy on a single port, so a self-hoster gets one URL per app. - A short "Self-hosting" section in
README.mdwith the exactdocker compose up -dcommands.
The part that's easy to get wrong: customHttp.yml
The Amplify config encodes real application behaviour, not just cosmetics. An nginx image would have to reproduce it, and I'd be happy to help get it right:
/and**/*.html→no-cache, max-age=0, s-maxage=0, must-revalidate/assets/*→public, max-age=31536000, immutable(Vite content hashes)/assets/*.wasm→ additionallyContent-Type: application/wasm(circuits,parametric,music-studio)/sw.js,/worker/*,/manifest.json→no-cache, ...(teamchat,fleet,legal,property-management,help-desk,solitaire,cad, and others)chess,backgammon,checkersadditionally ship a fullContent-Security-PolicyplusX-Content-Type-Options,Referrer-Policy,Permissions-PolicyandStrict-Transport-Security
Getting this wrong is not cosmetic: a stale sw.js pins returning users to an old build forever, and a missing application/wasm content type breaks the CAD / circuits / parametric engines outright.
Open questions
- Where should this live? One
Dockerfile+ compose file inside each of the 51 app folders is a lot of duplication. A shareddeploy/directory, or a single parameterizedDockerfiledriven by a build arg, might be cleaner — I'd like to follow the maintainers' preference here. - What about the worker components?
documents,spreadsheet,teamchat,help-desk,fleet,legalandproperty-managementhavebuild:worker/deploy:email-workerscripts targeting Cloudflare Workers. Should the compose file run those locally too (workerd/wrangler dev), or is the expectation that they stay external and just get documented? - How self-hosted is "self-hosted"? Several apps pull the Puter SDK from
https://js.puter.comand talk toapi.puter.com, and the shipped CSPs allow those origins. Should there be a documented path to point an app at a self-hosted Puter instance (cf.HeyPuter/puter), and would the baked-in CSPs need to become configurable?
Why it seems worth doing
The project's goal is free, open-source alternatives to proprietary software, and the audience for that is exactly the group that wants to self-host: home labs, small teams, privacy-sensitive organisations, people without an AWS account. docker compose up -d is the interface that audience already knows.
I'm happy to contribute a PR — for example documents and spreadsheet as a reference implementation, including the nginx header rules — if the approach is agreeable. Just wanted to check the direction before writing 51 near-identical Dockerfiles.
Checklist
- I have searched the existing issues and discussions for this and believe it is new
- I have read the contributing guidelines / README deployment notes
Activity
3Thanks @kamthorn — please go ahead, I'm not working on it.
I can't open a PR at the moment, so feel free to take the lead on the implementation if you're able to. Nothing to add against your proposal: a single parameterized Dockerfile in deploy/ driven by ARG APP, nginx config generated from customHttp.yml instead of hand-copied, and a short self-hosting section in the README all sound right to me, and I agree the root docker-compose.yml, the worker components and the self-hosted-Puter question are better handled separately.
If it's useful, I'm happy to review a PR or answer questions about the header rules I mapped out (the sw.js no-cache and application/wasm ones in particular). Thanks for picking this up.
Implementation in progress in https://github.com/HeyPuter/everything/pull/112 (Dockerfile + Compose + nginx profiles).
Thanks for the detailed write-up. I'd like to help with this, and I'm checking the direction before writing anything. @RXDCODX, you offered a PR too. Are you already working on it? If so I'll stay out of the way, or review.
What I'd propose for a first PR, answering the "where should this live" question:
Dockerfilein a rootdeploy/folder, withARG APP. It buildssrc/$APPwith Node 22 (npm ci && npm run build) and servesdist/from a non-root nginx image, with aHEALTHCHECK. This avoids 51 near-identical Dockerfiles.customHttp.yml, not copied by hand. That file already holds each app's cache,application/wasmand CSP rules, and Amplify reads it as the source of truth. A small script that turns an app's entry into an nginx config would keep the two deployments from drifting, which matters forsw.jsand the wasm content type.I'd leave these out of the first PR and handle them separately:
docker-compose.ymlwith a reverse proxy for several appsjs.puter.com/api.puter.comThe CSPs and the Puter SDK origin are probably a bigger discussion.
@jelveh, does this direction work for you (a shared
deploy/folder, generating the config fromcustomHttp.yml), or would you rather have something else? I'll start once I know.