Runs OpenVPS on AWS: one GPU instance that starts on demand and stops itself when idle.
There is no OpenVPS application code in here. This is CloudFormation, a Compose override and
some boot scripts. The instance clones upstream at a pinned commit when it boots, and
upstream's docker-compose.yaml runs unmodified, so moving to a new OpenVPS release is a
pin bump rather than a merge.
OpenVPS is MIT licensed, © 2025 Nokia, contributed to Open AR Cloud.
The stack, idle shutdown and FusionAuth are built and tested on real deployments. The waker is not built yet, so nothing is reachable from the internet; use SSM port forwarding to get at the services.
Tested means the services start healthy, both GPU containers see CUDA, and a full hloc reconstruction runs on the box. It does not mean the thing has been used in anger: no map has been built through the application's own API, nothing has been localized, no multi-GB upload has been tried and nobody has logged in. Those need a StrayScanner recording and real FusionAuth credentials. NOTES.md has the detail.
your domain (Route 53)
│
t4g.nano "waker" │ always on, ~$3/mo <- not built yet
Caddy holds the domain and terminates TLS
├─ GPU instance stopped -> holding page, then StartInstances
└─ GPU instance running -> reverse proxy
│
g4dn.2xlarge "openvps" started on demand
gp3 root 200 GB docker images and HLOC weights, survives stop
gp3 data 200 GB maps and the FusionAuth database, retained on stack deletion
backend · mapaligner · maplocalizer · frontend · fusionauth · postgres
idle-shutdown timer
One instance, on purpose. MapLocalizer serves one active map at a time so there is nothing
to scale out to, and keeping the ${MY_SHARED_MAPS_DIR} bind mount is what lets us track
upstream. No ECS, EKS, autoscaling, EFS or multi-AZ.
python3 deploy/aws/build.py # regenerates template.yaml from its sources
aws cloudformation create-stack --stack-name openvps-aws \
--template-body file://deploy/aws/template.yaml \
--capabilities CAPABILITY_IAM \
--parameters \
ParameterKey=VpcId,ParameterValue=vpc-xxxx \
ParameterKey=SubnetId,ParameterValue=subnet-xxxx \
ParameterKey=SecretsManagerArn,ParameterValue=arn:aws:secretsmanager:... \
ParameterKey=DomainName,ParameterValue=vps.example.orgFirst boot takes about 25 minutes: clone, HLOC submodules, four image builds, container start. There is no SSH and no key pair; access is through SSM Session Manager.
Check the AZ before you pick a subnet. The retained maps volume pins the availability zone permanently and GPU capacity is scarce, so read Choosing an AZ first.
Running cost is roughly $39/month standing plus $0.75 per awake hour, so about $85/month at two hours a day.
- deploy/aws/README.md — how to deploy, resize, migrate and tear down
- deploy/aws/NOTES.md — measurements, and every bit of friction we hit
template.yamlis generated bybuild.py; edittemplate.src.yamlinsteaddocker-compose.aws.yamlis the only place upstream behaviour is changedfusionauth/,nginx/,scripts/,systemd/— the identity provider, config and boot logic
No secrets live in this repo, the template or user-data. They sit in Secrets Manager and are fetched at boot by the instance role.
MIT, see LICENSE. Copyright (c) 2026 Open AR Cloud.
No upstream code is vendored here. The one derived file is
deploy/aws/nginx/mapbuilder.conf, adapted from upstream's
mapbuilder/Frontend/nginx.conf and marked as such.