Skip to main content

Cloud Deployment

The cloud:* namespace covers the journey from local development to a production-grade VPS. These commands graduate your project from .kube to a real domain on a real cluster.

Pairs with the deployment guides

For the full graduation story, see The Scaling Journey, the Single-Node Hero $6/mo baseline, and GitHub Actions for CI/CD wiring. Don't have infrastructure yet? cloud:create provisions it for you.

cloud:create {environment?}

The "Infrastructure Provisioner." Creates the droplet or managed cluster itself via OpenTofu (or Terraform), then hands off to cloud:init / cloud:init:doks — no more bringing your own pre-existing box. See Provisioning with OpenTofu & Terraform for how it works and Provisioning Infrastructure for the walkthrough.

  • Flags: --provider=do, --vps (droplet + k3s) or --managed (DOKS).
  • New or attach: offers to provision a new stack, or attach the given environment to an existing registered one.
  • Aliased as: cloud:new.

cloud:destroy {stack?}

Tears down a stack provisioned by cloud:createtofu destroy plus removal from the global registry.

  • Warns if any environments are still bound to the stack.
  • Distinct from cloud:nuke: this deletes the infrastructure itself; cloud:nuke only wipes an app's resources and leaves the box/cluster running.

cloud:stacks

Lists every OpenTofu-provisioned stack registered on this machine — kind, region, IP/context, and bound environments.

cloud:init

The "VPS Bootstrap." Secures and prepares a fresh VPS for LaraKube. Installs K3s (Single-Node), hardens the firewall, configures the deploy user, and sets up the LaraKube Local CA.

  • Target: A bare Ubuntu/Debian VPS (DigitalOcean droplet, Hetzner CX11, Vultr, etc.) — or one just created by cloud:create --vps, which runs this automatically.
  • Result: A cluster-ready box that cloud:configure and cloud:deploy can target.
  • One-time per VPS: Run once when you stand up a new server.

cloud:configure

The "Pipeline Setup." Configures the server and deployment pipeline for a specific project on a provisioned VPS.

  • What it sets up: GHCR registry credentials, the namespace for your project, the production-shape Kubernetes manifests, environment-specific secrets and configmaps.
  • Per-project: Run once per project per environment (e.g., production, staging).

cloud:deploy {environment}

The "Release" button for remote environments. Builds and deploys your application to a remote cluster.

  • CI/CD Integration: Designed to work seamlessly with GitHub Actions (see GitHub Actions).
  • Environment Targeting: Specify the target environment as an argument (e.g., larakube cloud:deploy production).
  • Zero-downtime rolls: Uses Kubernetes' standard rolling update strategy.

cloud:nuke {environment}

The "Remote Cleanup." Wipes all project resources from the remote cluster — namespace, PVCs, services, ingresses.

  • Destructive: Everything the project deployed to the cluster is removed. The cluster itself stays up.
  • Use when: Decommissioning a project or starting over after a major architectural change.
  • Confirmation: Requires explicit confirmation.

cloud:externalize {environment}

The "Go Multi-Node" helper. On multi-node-ha, app pods run stateless (per-pod ephemeral storage), so state must live outside them. This rewrites an environment's state drivers to do exactly that — turning the requirement into one guided step. cloud:deploy also offers to run it when it detects local state on a multi-node env.

  • What it changes: in .env.{env} it flips SESSION_DRIVER / CACHE_STORE / QUEUE_CONNECTION and FILESYSTEM_DISK=s3. It writes only these selector keys — never the connection values (AWS_*, REDIS_*), so a Commons or self-hosted connection is never clobbered.
  • Sessions & cache: pick Redis, Memcached, or Database (the driver enum decides the values; Database is hidden when the primary DB is SQLite, since that can't span nodes).
  • Backends — three ways: when S3/Redis aren't already wired it asks where they come from — join a Plex Commons (offered only when one is actually initialized on that env's cluster), self-host them in-project (reuses larakube add), or managed/external (you set the creds). If a backend is already wired, it shows you the source (e.g. "sessions & cache (redis) → Plex Commons") instead of silently accepting.
  • SQLite: detected and called out — SQLite can't go multi-node, so it offers to switch to a networked engine first (Postgres/MySQL/MariaDB).
  • Idempotent: re-running on an already-externalized env is a no-op. After it runs, redeploy to apply.

See Storage across the scaling journey.

cloud:init:nfs

The "Shared Folder" escape hatch for multi-node clusters. Installs an in-cluster NFS provisioner so an environment can opt in to ReadWriteMany (RWX) shared storage instead of the stateless default — see Storage across the scaling journey.

  • What it installs: a single NFS server (a block volume re-exported over NFS) plus a dynamic provisioner, exposed as the larakube-nfs StorageClass. After it's installed, set "sharedStorage": true on the environment and redeploy.
  • Flags: --context, --size=10Gi (backing block volume), --storage-class= (block class for the backing volume; defaults to the cluster default, e.g. do-block-storage), --retain (keep the PV on PVC delete).
  • Idempotent: the larakube-nfs StorageClass is the marker — a completed install is a no-op. (If an install half-fails, delete the StorageClass before re-running.)
Experimental — not for DOKS

The NFS server is a single pod (a soft storage SPOF — your app pods stay HA) and depends on the node's NFS mount path, which does not work on DigitalOcean Kubernetes (DOKS): the mount hangs. Prefer externalizing state to object storage + Redis; reach for this only when an app needs a genuine shared cross-node folder.