Oracle Cloud · Mumbai · Ampere A1

Ridgeserve Lab

A single always-on ARM box running a DevOps track end to end — own git server, own CI/CD, GitOps, monitoring, infrastructure as code and a secrets store. Everything on it is configured from one git repo, never by hand.

Host
abhishekdevlopment
Address
144.24.122.201
CPU
4 OCPU arm64
Memory
24 GB
Disk
193 GB
OS
Ubuntu 24.04

Running services

Anything marked local is reachable only over SSH — no port open to the internet.

This page

Live
ridgeserve.duckdns.org

Served by nginx from /var/www/ridgeserve. Later services get their own subdomain.

Vault

Tunnel

vault namespace · standalone

Real seal lifecycle, not dev mode. Needs unsealing by hand after any restart.

Actions runner

Live

ridgeserve-runner · arm64 · 2 jobs

Labels ubuntu-latest and node-22. Builds run in containers on the host daemon.

PostgreSQL 16

Tunnel

127.0.0.1:5432 · db ecomersehub

Reached through a tunnel that reopens itself at Windows login. TLS is configured on the server, but the port stays closed.

Practice stack

Tunnel

devops/compose/hello

Four containers — nginx, python, postgres, redis — for poking at Compose.

OCI CLI

Ready

~/.local/bin/oci

Authenticated with your own API key, so cloud resources can be managed straight from the box.

The track

Each phase is installed when you reach it, so nothing idles.
00 Foundation — languages, tooling, the devops repo Done
01 Containers — docker, compose, buildx Done
02 Git server and CI/CD — gitea, gitea actions, nginx, lets encrypt Done
03 Kubernetes — k3s, kubectl, helm, k9s Done
04 GitOps — argocd Done
05 Observability — prometheus, grafana, loki Done
06 Infrastructure as code — opentofu on real OCI, ansible Done
07 Security — vault, trivy Done

Toolchain

ToolVersionNotes
Go1.27.0The language most of this stack is written in
Node.js22.23.2npm 10.9
Python3.12.3pip, venv, uv 0.12
Java21.0.12OpenJDK
Docker29.7.2Compose v5.5.0, buildx
k3s1.36.3Single node, Traefik disabled
Helm3.21.4—
k9s0.51.0Terminal UI for the cluster
ArgoCDstableAuto sync, prune, self-heal
Prometheus7d retention13 targets scraped
Grafana29 dashboardsPrometheus + Loki datasources
Lokisingle binary7 day log retention
OpenTofu1.12.6Manages real OCI resources
Ansible2.16.3Describes this server
Vaultstandalonekv-v2 at path lab/
Trivy0.74.0Blocks HIGH/CRITICAL in CI
PostgreSQL16.15TLS on, localhost only
nginx1.24.0Holds port 80 and 443
SQLite3.45.1—
Certbot2.9.0Renewal timer active

Commands worth keeping

Getting in

ssh oracle
Also answers to oracle-big. Key based, no password.
ssh -L 3000:127.0.0.1:3000 oracle
Forward any localhost-only service to your own machine.

Containers

lazydocker
The fastest way to see what is actually running.
docker compose ps
Run it inside a stack directory under ~/devops/compose.
docker compose logs -f
Follow output while something misbehaves.

Kubernetes

k9s
Browse pods, logs and events without memorising flags.
kubectl get pods -A
Everything running, every namespace.
kubectl apply -f ~/devops/k8s/demo
Files are numbered so they apply in dependency order.

Web and certificates

~/devops/scripts/deploy-nginx.sh
Copies configs from the repo to nginx and reloads. Edit the repo, never /etc.
sudo certbot certificates
Which certificates exist and when they expire.

The database tunnel

Get-NetTCPConnection -LocalPort 5432
On Windows — confirms the tunnel is up.
Get-Content ~\.ssh\pg-tunnel.log -Tail 20
What the supervisor has been doing.

Things that will bite you

The free trial converts on about 22 September.

Always Free allows 2 OCPU and 12 GB of Ampere. This box is 4 and 24, which counts as paid, so it is reclaimed around 22 October unless you either upgrade to Pay As You Go — where the same 4 and 24 is free — or shrink it to 2 and 12. Your card is never charged without you pressing upgrade.

Opening a port takes two separate changes.

An OCI Security List rule and an iptables rule. Miss either one and traffic just disappears. A Security List block times out; a host with nothing listening refuses instantly — that difference tells you which layer to fix.

Never change the SSH port through ssh.socket.

Overriding ListenStream drops the IPv4 listener while ss still looks healthy. That locked this box out for an hour and needed a boot-volume rescue.

k3s cannot see images Docker built.

They live in different image stores — Docker's and containerd's. A locally built tag that works with docker run will fail to pull in a pod. The fix is a registry both sides can reach, which is what Gitea's built-in one is for.

nginx owns ports 80 and 443.

k3s was installed with Traefik disabled so nginx stays the front door and keeps the certificate. Cluster services are reached through NodePorts that nginx proxies to.

Secrets live outside git on purpose.

.env files and .pg-*.creds are ignored, so the repo alone cannot rebuild the server. Phase 7 fixes that properly with Vault.