Build Replit
KINDAreplaces $25/mosaves $300/yrback to the verdict
code-server behind authentication and TLS, one container per project so a runaway process cannot take the machine down, secrets injected at runtime rather than written into workspaces, a template system for new projects, and a deploy command that publishes a project to a real URL.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- have ready10 to 40 USD a month depending on how many projects run at once
Why Each project is a container with its own memory allowance, so capacity is the number of projects multiplied by their limits.
Get it Any virtual server provider. Start with something modest and size up once you know how many projects you actually keep.
Verify
free -m shows enough memory for your intended project count and limits - installfree
Why Isolation, limits and lifecycle all come from the container runtime.
Get it Install from Docker's own repository rather than a distribution package, which is often behind. open ↗
Verify
docker compose version reports v2 or higher - have readyroughly 10 to 15 USD a year
Why Each project gets a subdomain, and a wildcard certificate needs a DNS challenge with a provider API token.
Get it Any registrar with DNS API access. Add a wildcard record and create a scoped token.
Verify
A wildcard hostname resolves and the token can create a TXT record - decidefree
Why A browser development environment is a remote shell. Deciding whether it is only you, a small trusted group, or anyone changes every isolation decision.
Get it Write down who will have accounts and what happens if one is compromised. If the answer is anything beyond a small trusted group, revisit the isolation model before Phase 2.
Verify
The access decision is written down before Phase 1 is deployed - accounta few USD a month
Why Workspaces are people's work and the secret store exists nowhere else. Both die with the server otherwise.
Get it Object storage with credentials scoped to one bucket.
Verify
A test file uploads and lists from your laptop
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- This is infrastructure, so the state worth writing down is operational. - projects(id, name, subdomain, image, cpu_limit, memory_limit, created_at, last_active_at) - volumes · one per project, holding the workspace, backed up on a schedule - secrets · per project, stored encrypted outside any workspace, injected at container start - templates · base images and starter files per language - sessions · who is authenticated, and to which projects
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
BASE_DOMAIN | required | dev.example.com | Projects are served at subdomains of this. |
DNS_API_TOKENsecret | required | replace-with-provider-token | Needed for wildcard certificate issuance through a DNS challenge. |
PROJECT_MEMORY_LIMIT | required | 1g | Per-container memory ceiling. Unset means unlimited, which is how one project takes down the host. |
PROJECT_PIDS_LIMIT | required | 200 | Per-container process limit. This is what stops a fork bomb. |
SECRET_STORE_KEYsecret | required | generate-a-long-random-value | Encrypts the secret store at rest. Losing it loses every project's secrets, so it belongs in your password manager and in the backup. |
IDLE_STOP_MINUTES | required | 60 | How long a project may sit idle before its container is stopped. |
BACKUP_DEST | required | s3://your-bucket/dev | Where volumes and the secret store are copied nightly. |
The build, in order
One editor, behind a locked door
code-server runs and is reachable only after authentication, over TLS.
Non-root user, key-only SSH, firewall allowing SSH and the web ports. Verify with a scan from elsewhere.
terminalufw allow OpenSSH && ufw allow 80,443/tcp && ufw enable nmap -Pn YOUR_SERVER_IP
Publish only to 127.0.0.1 so nothing reaches it except through the proxy.
terminaldocker run -d -p 127.0.0.1:8080:8080 -v ~/project:/home/coder/project codercom/code-server:latest
Certificate and an authentication layer. Test the unauthenticated path before celebrating the authenticated one.
Files
Caddyfile
done when · tick each as it passeswatch out- A code-server instance reachable without authentication is a remote shell on your server offered to the internet, and these get found by scanners within hours rather than days. Put authentication in front before the port is ever reachable, not after you have confirmed the editor works.
One container per project
A runaway process in one project cannot take down the server or reach another project.
Memory, process count, open files and CPU shares. Defaults are unlimited, which is the problem.
terminaldocker run -d --memory=1g --pids-limit=200 --cpus=1 ...
One volume per project, no privileged flag, no host mounts, a non-root user inside.
Files
compose/project.ymlExhaust memory, fork bomb, and attempt to read a sibling project. Each should fail in a contained way.
done when · tick each as it passeswatch out- A container without a memory limit will happily consume the host's memory until the kernel starts killing processes, and the process it kills may well be something else important. Set memory, process count and open file limits explicitly, then test each one by exceeding it on purpose.
Secrets that do not end up in git
A project can use an API key without that key being anywhere in the workspace.
Encrypted at rest, per project, on the host or in a secret manager. Never inside the volume.
Files
src/secrets.tsEnvironment variables passed to the container. Nothing is written into the workspace at any point.
Files
compose/project.ymlA recursive grep of the workspace for the secret value, run as a test. Absence is the feature.
Files
test/secrets.sh
done when · tick each as it passeswatch out- A secret written into a .env file inside the workspace is inside a git repository the moment the user runs git init, and workspaces are exactly what people push. Inject at container start so the value exists in the process environment and never in a file the user can commit.
Templates and a new project in one command
Starting a project takes seconds rather than an afternoon of setup.
Runtime, package manager and common tools baked in. Rebuild on a schedule to pick up security updates.
Files
images/Volume, container, route, certificate and starter files in one action, reporting how long it took.
Files
src/create.tsContainer, volume, route, certificate and secrets. A partial delete leaves a subdomain pointing at nothing and secrets nobody is using.
Files
src/delete.ts
done when · tick each as it passeswatch out- Installing a language runtime on first use inside a generic container means every new project starts with several minutes of downloading. Bake the runtime into the image so a new project is ready in seconds, and rebuild images on a schedule rather than at project creation.
Deploying what you built
A project goes from editor to a public URL with one command.
From the project source, not from the development container. Different container, different limits, no editor.
Files
src/deploy.tsSeparate from the development subdomain, with its own certificate.
Files
CaddyfileRetain the prior image and a rollback command. Test by deploying something broken.
Files
src/rollback.ts
done when · tick each as it passeswatch out- Serving the development container publicly means the editor, the workspace and any process the user started are all exposed on the public URL. Deploy a separate container built from the project, and keep the development environment private.
Backups, idle shutdown and the restore drillproduct builder
Workspaces survive the server, and idle projects stop consuming it.
Dated, several generations, off the machine. The secret store is encrypted and still belongs off-site.
Files
scripts/backup.shTrack last activity and stop after a threshold. Start on the next request, accepting the cold start.
Files
src/idle.tsBoth halves, then open the project and confirm a secret-dependent command works. Record the date.
Files
README.md
done when · tick each as it passeswatch out- Backing up volumes without the secret store gives you a restore where every project is present and none of them can reach their APIs, and the secrets exist nowhere else by design. Back up both, and treat the secret store as the more important half.
That is the whole plan for Replit. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- The zero-setup experience, since setup is now yours.
- Hosted agents that run without your machine.
- Multiplayer editing in the browser.
- Instant scaling under load.
- zero-setup browser IDE
- hosted agents
- multiplayer
- templates
- deployments
- education/community workflows
- Ephemeral preview environments created per branch
- A shared base image cache to cut project creation time further
- Per-project resource usage reporting, so limits can be set from evidence
Need the files? The project pack on the verdict page hands your agent the whole brief · more dev tools.