Dockerized OCI free-tier capacity watcher that retries until your target VM profile is provisioned.
- Reads OCI credentials from a mounted
.ocidirectory (read-only) - Uses a chosen
OCI_PROFILEfrom mounted config - Creates/reuses dedicated compartment + network resources
- Uses a shared JSON profile defaults file for compute/LB behavior
- Retries compute launch until capacity is available
- Sends one-time success notification (optional)
Compute and LB profile is loaded from profile.defaults.json (mounted via PROFILE_DEFAULTS_FILE):
- A1 count/shape sizing
- Micro count/boot size
- Free LB enable flag and display name
LB bandwidth is fixed to Always Free 10 Mbps in code.
For Always Free LB details and setup guidance, see:
This project is built for hostile-ish hosts with least-privilege defaults:
- No credentials in image or repo
- Credentials mounted read-only from host (
/run/oci) - Read-only root filesystem
tmpfsfor/tmpcap_drop: [ALL]no-new-privileges
Important: if host root is compromised, mounted credentials can still be exfiltrated. Use a scoped OCI user/key and rotate regularly.
none(default)unraid(mount and call Unraid notify binary)webhook(HTTP POST)
- Release workflow creates immutable tags in the format
vYYYY.MM.DD.N. - Image workflow publishes
ghcr.io/syscode-labs/oci-free-tier-docker-capacity-watch:<tag>for each release tag. latestis also published for convenience, but production use should pin an immutablev...tag.
docker-compose.ymlprofile.defaults.jsonworker/provision_free_tier_retry.pyworker/entrypoint.sh.env.exampleMakefile.mise.tomlQUICKSTART.md
See QUICKSTART.md for setup.
First run in a new clone:
mise trust
mise env-genUseful tasks:
mise env-gen- create.envif missing and validate compose configmise env-gen-force- recreate.envfrom template and validatemise env-check- validate local env paths/profile JSON and compose renderingmise apply- run watcher in foreground