Deploy on Oracle Cloud Free Tier
Oracle Cloud Always Free tier provides permanent VMs — enough to run dinary indefinitely at zero cost.
Pricing
| Resource | Free Tier Allocation | Cost |
|---|---|---|
| AMD Micro VM | 2 instances, 1 OCPU + 1 GB RAM each | $0 forever |
| ARM Ampere A1 VM | Up to 4 OCPU, 24 GB RAM (shared pool — often unavailable) | $0 forever |
| Boot volume | 200 GB total | $0 |
| Outbound data | 10 TB/month | $0 |
| Total | $0/month |
Which shape to choose
AMD Micro (VM.Standard.E2.1.Micro, 1 GB RAM) is recommended — it is almost always available because Oracle reserves a dedicated pool for free-tier accounts. 1 GB RAM is enough for FastAPI without Docker.
ARM Ampere A1 (VM.Standard.A1.Flex, up to 24 GB RAM) is more powerful but often unavailable ("Out of host capacity"). If you get one — great, otherwise use AMD Micro.
Warning
Oracle may reclaim idle Always Free instances. Running a lightweight server like dinary keeps the instance active. If reclaimed, you can recreate the VM, but the runtime source of truth is data/dinary.db on disk, not Google Sheets. Back up ~/dinary/data/ before destructive work and do not treat the sheet-logging spreadsheet as a full restore source.
Prerequisites
- A Google service account JSON key at
~/.config/gspread/service_account.json— see Google Sheets Setup. - An SSH key pair for connecting to the VM.
1. Create an account
- Go to cloud.oracle.com → Sign Up.
- Select your home region (cannot be changed later).
- Complete verification (credit card required but never charged for Always Free resources).
Region selection
Your home region is permanent. ARM instance availability varies by region. Community reports suggest Ashburn, Phoenix, Frankfurt, and London tend to have better ARM availability. However AMD Micro instances are available in all regions.
Note
Account approval can take hours to days.
2. Set up networking (VCN)
Oracle VMs need a Virtual Cloud Network (VCN) with a public subnet and internet gateway. Create these before the VM:
-
Go to Networking → Virtual Cloud Networks → Create VCN.
- Name:
dinary-vcn(or any name) - IPv4 CIDR Blocks:
10.0.0.0/16 - Click Create VCN.
- Name:
-
Inside the new VCN → Subnets → Create Subnet.
- Name:
public-subnet - Subnet type: Regional
- IPv4 CIDR Block:
10.0.0.0/24 - Subnet access: Public Subnet
- Click Create Subnet.
- Name:
-
Inside the VCN → Internet Gateways → Create Internet Gateway.
- Name:
internet-gw - Click Create Internet Gateway.
- Name:
-
Inside the VCN → Route Tables → click the default route table → Add Route Rules.
- Destination CIDR Block:
0.0.0.0/0 - Target Type: Internet Gateway
- Target: select
internet-gw - Click Add Route Rules.
- Destination CIDR Block:
3. Create a VM
- Go to Compute → Instances → Create Instance.
- Configure:
- Image:
Canonical Ubuntu 22.04 Minimal(for AMD Micro — withoutaarch64in the name) - Shape:
VM.Standard.E2.1.Micro— 1 OCPU, 1 GB RAM - Capacity:
On-demand capacity - Availability / Live migration:
Let Oracle Cloud Infrastructure choose the best migration option - Networking: select
dinary-vcn→ selectpublic-subnet→ check Automatically assign public IPv4 address - SSH keys: upload your public key
- Cloud-init script: leave empty
- Image:
- Click Create.
ARM alternative
If ARM capacity is available, you can choose Canonical Ubuntu 22.04 Minimal aarch64 + shape VM.Standard.A1.Flex (1 OCPU, 6 GB RAM). More RAM allows running Docker if desired. The rest of the setup is the same.
4. Configure .deploy/.env
All per-instance configuration (everything that is not committed to the repo) lives under the .deploy/ directory at the repo root. After the VM is created, copy the public IP from the Oracle dashboard and create .deploy/.env on the laptop:
mkdir -p .deploy
cp .deploy.example/.env .deploy/.env
Edit .deploy/.env:
DINARY_DEPLOY_HOST=ubuntu@<PUBLIC_IP>
# DINARY_TUNNEL=tailscale # tailscale (default) | cloudflare | none
# DINARY_SHEET_LOGGING_SPREADSHEET=https://docs.google.com/spreadsheets/d/YOUR_ID/edit
inv setup-server syncs the local .deploy/.env to the VM under
/home/ubuntu/dinary/.deploy/ and seeds the runtime taxonomy via
inv bootstrap-catalog --yes.
Verify SSH access:
ssh ubuntu@<PUBLIC_IP>
5. Setup
From your laptop, in the dinary repo:
inv setup-server
This single command performs everything on the VM via SSH:
- Installs system packages (python3, git)
- Installs uv (Python package manager)
- Clones the repo and installs dependencies
- Syncs your local
.deploy/.envto the VM - Uploads
~/.config/gspread/service_account.jsonto the VM - Creates and starts a
dinarysystemd service - Sets up the tunnel (Tailscale by default, or Cloudflare — depending on
DINARY_TUNNEL)
To seed categories to the DB call inv bootstrap-catalog --yes.
Tailscale (default)
During setup, tailscale up prints a URL — open it in your browser to log in (create a free account if needed).
Enable HTTPS in the admin console:
- Enable MagicDNS (if not already enabled).
- Enable HTTPS for your tailnet.
The app will be reachable at https://<machine-name>.<tailnet>.ts.net — tailnet only, Tailscale must be running on the client device.
First launch: wait up to 10 minutes
On first launch, Tailscale provisions a TLS certificate and propagates DNS. The URL may return ERR_SSL_PROTOCOL_ERROR for several minutes. Wait and retry.
Cloudflare
Set DINARY_TUNNEL=cloudflare in .deploy/.env before running inv setup-server. During setup, cloudflared tunnel login will prompt you to authenticate in the browser. Requires a domain managed by Cloudflare DNS — see Cloudflare Tunnel & Access.
No tunnel
Set DINARY_TUNNEL=none to skip tunnel setup. You'll need to open firewall ports manually:
VCN Security List: add ingress rule — Source 0.0.0.0/0, Protocol TCP, Port 8000.
OS firewall:
ssh ubuntu@<PUBLIC_IP> 'sudo iptables -I INPUT -p tcp --dport 8000 -j ACCEPT && sudo netfilter-persistent save'
Maintenance
| Command | What it does |
|---|---|
inv deploy |
Pull latest code, sync deps, apply migrations, restart service |
inv bootstrap-catalog --yes |
Re-seed the runtime taxonomy (use when taxonomy changes; overwrites manual edits) |
inv status --remote |
Show dinary and tunnel service status |
inv logs --remote |
Tail dinary server logs |
inv setup-server |
Full re-setup (safe to re-run) |