Indie hacker's JS runtime with production live-reload.
Launch always-up-to-date backends in one line of code like it's 2009 again.
- if you want to have a single source of truth in your git repository codebase
- if you want to have a serverless experience without the drawbacks of vendor lock-in
- if you don't like to wait minutes while your CI/CD pipeline is building the latest image
Delivering your web app to the actual users is a journey. Yes, you have the code working locally. Yes, you have a git repo somewhere on GitHub with the latest version of the code. But how do others access it?
This is a solved problem for frontend and static files: you just push the code and use any available CDN to serve it. But what about the backend?
OLS is a self-hosted serverless Deno runtime with automatic live-reload from a git repository. The basic idea is that you run a single command on your production server and never have to maintain it anymore.
OLS is meant for small to medium-sized projects that don't want to or can't afford to maintain complex infrastructure with advanced GitOps.
- Launch with an example repo:
docker run -p 9000:9000 -e OLS_REPO="https://github.com/zlumer/ols.git" -e OLS_WORKERS_ROOT="/routes" zlumer/ols:latest- Check that the runtime is running and workers execute:
curl http://localhost:9000/hello?name=AliceOr open http://localhost:9000/hello in the browser.
OLS is a Deno runtime with an HTTP router on top of it. It automatically pulls from a git repository under a specified branch, making sure that you're always running the latest version of your code in production.
You can write your own workers in Deno and they will be automatically executed by OLS.
Local dev mode automatically reloads all workers on every request.
To enable dev mode, pass OLS_DEV_MODE=1 in env and make sure to remove OLS_REPO.
docker run -it --rm -p 9000:9000 -e OLS_DEV_MODE=1 -v ./routes:/app/workdir zlumer/ols:latestOLS is in an early alpha release, but it is ultimately meant for production use. The philosophy of OLS is "launch and forget", meaning that you run a single command on your remote machine and never have to maintain it anymore.
Production checklist:
- You would probably use
--env-fileinstead of-eto pass the environment variables. - Always tag a specific version of OLS Docker image, not
latest. E.g.zlumer/ols:v0.0.1 - Set Docker restart policy to
unless-stoppedor use Docker Compose. - Set up a reverse proxy (e.g. Nginx) to handle SSL and other HTTP features.
Environment variables:
- Make sure that you provide
OLS_REPOand notOLS_DEV_MODE. - Set
OLS_WORKERS_ROOTandOLS_BRANCH_NAMEto production values. - Update
OLS_POLLING_INTERVALto an appropriate value (the default65is optimized for GitHub).
Test that the workers are responding after OLS is launched. Set up an uptime monitor to periodically check that the OLS instance is running.
docker run -d --restart unless-stopped --rm -p 9000:9000 --env-file ./.env zlumer/ols:v0.0.1<TODO>tldr: Use different branches and environment variables to manage different environments.
| Name | Default Value | Description | Environment |
|---|---|---|---|
| OLS_DEV_MODE | false | Enable DEV mode | dev |
| OLS_REPO | Repository URL | prod |
|
| OLS_BRANCH | master |
Branch name in the repository where the code is located | prod |
| OLS_WORKERS_ROOT | / |
Path to workers root directory in the repo (or in the workdir in DEV mode). | both |
| OLS_POLLING_INTERVAL | 65 |
Repository polling interval in seconds. If you have a local git mirror, feel free to set this to lower values, e.g. 1. If you are using a cloud repo and get rate-limited, use lower values. |
prod |
| Path | Description |
|---|---|
/app/.env |
Environment variables for workers. Live reloading so you don't need to restart the service after you change env. |
/app/workdir |
(dev only) mount your workers here |
/app/repo |
Repository will be cloned to this directory (under ./blue and ./green subdirs), you can cache it if you have a large repo that takes too long to clone from scratch. |
OLS instances should generally be stateless, meaning that you can launch as much of them as you want.
If you launch multiple OLS instances, you'll need a load balancer on top of it. Nginx works perfectly for a single-location scalability.
If you launch in multiple geographical regions, you'll need your load balancer to automatically find the closest instance to the user. Cloudflare Load Balancer geo steering can help with that. However, if you find yourself maintaining multiple OLS regions, it might be time for you to switch to the edge serverless such as Cloudflare Workers.
(basically a simple HTTP router on top of Supabase Edge Runtime/Deno and a git polling job)
To set up a modern backend in 2024 you have two main options:
-
Use a cloud provider's serverless offering (Cloudflare Workers, Deno Deploy, Vercel Functions, etc). This is usually a great choice, but there are certain drawbacks:
- vendor lock-in, meaning that you can't easily switch to another provider or your own infrastructure
- serverless costs might get extremly high, especially during surges in traffic
- you still have to set up a CI/CD pipeline to deploy your code
- with the exception of Cloudflare, almost no clouds provide a good worldwide geographical coverage, meaning that you might not have a serverless instance close to your users; this is especially true in remote areas where even Cloudflare doesn't have a data center
-
Alternatively, you can set up your own infrastructure. An example of such a setup is:
- GitHub Actions to build and push Docker images
- Docker Hub or ghcr.io to store Docker images
- Docker Compose or Kubernetes to run the containers
- set up container registry secrets in your CI/CD
- set up k8s ingress for routing
- you pay for basically every step above: CI/CD minutes, Docker Hub, k8s control plane, etc.
- maintaining separate dev/staging/production environments adds complexity
- due to CI/CD pipeline and container restart times it is not uncommon to have a 15-30 minutes delay between pushing a commit with a single line fix and seeing the changes live
If this sounds like a crazy amount of work for a simple backend, it's because it is.
With OLS you get the serverless experience without the drawbacks of vendor lock-in and serverless horrors.
And the best part is that if you decide to move to k8s when your team expands, you can launch OLS in your k8s cluster and it will work just fine.
Workers cannot access file system.
- Blue/green deployments
- Separate env vars source for workers
- Manifest file to replace CLI args
- Shorter launch command (e.g.
yarn ols:launchor./ols.sh <path to manifest>) - Docs: Docker Compose example
- Docs: DB connection example
- Docs: Dev/Staging/Production Environments example
- Docs: how to write workers
- Docs: how to set up a reverse proxy & SSL
- Docs: how to set up a custom domain
OLS is based on Supabase Edge Runtime which is based on Deno.