This is a minimal prototype of a Node.js hosting platform written in Go.
- User register/login (SQLite)
- Upload zipped Node.js project (server-side)
- Attempts to
npm installand run the app (triesnpm startthennode index.js) - Reverse proxy by Host header to the app's allocated port
- Security: This project runs untrusted code directly on the host. This is extremely dangerous in production. Use containerization (Docker/LXC) and strict resource limits before exposing publicly.
- Requirements on host:
- Go 1.21+
- Node.js and npm available in PATH
- sqlite3 (bundled as lib via Go driver)
- Ports: The app allocates ports starting at 30000. Ensure your firewall allows these local ports.
-
Build:
go build -o nodehost -
Run:
./nodehostThe server listens on port 8080.
-
Point your custom domain's A record to the server IP and create an HTTP server/port forwarding so requests reach this Go server. The app will reverse-proxy requests based on the Host header.
- This is a developer prototype. For a production-ready system you must:
- Run each app inside isolated container (Docker)
- Implement resource limits and user quotas
- Use HTTPS (Caddy or Let's Encrypt)
- Validate and sanitize uploads
This repository now includes a helper script scripts/run_app_container.sh and a docker-compose.yml.
nodehostservice runs the Go server (listens on 8080).caddyacts as a fronting reverse proxy (ports 80/443) and forwards requests tonodehost.- Each uploaded app should be run in its own Docker container to provide isolation. This repo includes a helper script (not fully automatic) that starts a container for a given user/app and maps a host port to the container.
-
Build and start the services:
docker compose build docker compose up -dNote: This will mount
/var/run/docker.sockinto the nodehost container so it can interact with Docker. This is convenient but very dangerous (gives root-level access to Docker host). A safer option is to run the helper script from the host machine instead of inside the container. -
Upload an app through the web UI (or place files into
apps/<user_id>/<appname>/). -
Start the app in a container (from host machine, recommended):
./scripts/run_app_container.sh <USER_ID> <APP_NAME> <HOST_PORT> [INTERNAL_PORT]Example:
./scripts/run_app_container.sh 2 myapp 31000 3000This will:
- Bind-mount
./apps/2/myappinto the officialnode:18image - Run
npm install --production - Start
node index.jsinside the container - Expose the container on host port
31000
- Bind-mount
-
Add a DNS record for your custom domain that points to the server IP, then in the
appstable (or via dashboard) set thedomaincolumn to your custom hostname. The fronting Caddy will forward the Host header to nodehost which will route to the app port.
- Do not expose
/var/run/docker.sockto untrusted code. Prefer running container orchestration from the host or via a dedicated service account. - Use resource limits for containers (CPU, memory) — the helper script doesn't set these.
- Use non-root images for running apps where possible.
- Use a proper orchestration or sandbox (containerd, Kubernetes, Firecracker) for production workloads.
When a user uploads a ZIP and the server extracts it, the server will now
attempt to automatically start the app using scripts/run_app_container.sh.
The app will be exposed on the allocated host port (starting from 30000) and
Caddy will route requests by Host header to the corresponding port.
The project now includes multiple production-focused measures:
-
Upload validation & limits
- Max upload size: 25 MB.
- Per-user app limit: 5 apps.
- App names sanitized (only alphanumeric, -, _).
- Requires
package.jsonpresent (to ensure Node app).
-
Build-per-app Docker image
- Each upload is built into a Docker image inside the app directory (minimal runtime Dockerfile).
- The runtime image runs as a non-root user (
appuser).
-
Strict runtime flags
- Containers launched with:
--read-only,--tmpfs /tmp,--cap-drop ALL,--security-opt no-new-privileges--pids-limitto limit process count- Memory and CPU limits (
--memory,--cpus) - Run as non-root user (
--user 1000:1000)
- Consider applying AppArmor or SELinux profiles and a custom seccomp JSON for further restrictions.
- Containers launched with:
-
Avoid exposing Docker socket
- This setup builds images and runs containers but does not require the Go service to have direct access to the host Docker socket if you run the helper script from the host.
- If you must allow the Go service to launch containers, use a docker API proxy with restricted permissions or a dedicated service account.
-
Network isolation
- Use user-defined Docker networks and firewall rules to isolate app containers from sensitive infrastructure (databases, metadata services).
- Consider using an ingress proxy (Caddy/Traefik) that performs TLS termination and request filtering.
-
Monitoring & quotas
- Track container statuses in DB (apps table includes status and container_name).
- Add alerting for high CPU/memory, and implement disk quotas for user uploads.
-
Scanning & sandboxing
- For production, incorporate malware scanning and static-analysis of uploaded contents.
- Use kernel-level virtualization (gVisor, Firecracker) or orchestrators (Kubernetes) for stronger isolation.