::once
once is a BigConfig package for ONCE. This BigConfig package is an infrastructure automation tool that simplifies the provisioning and configuration of cloud resources using OpenTofu and Ansible. The audience is the vibe coder who wants to deploy his vibe coded application with a “one-click” experience.
It is built on top of big-config, leveraging its workflow and configuration management capabilities.
Features
Section titled “Features”- End-to-End Orchestration: A seamless six-stage workflow:
- Infrastructure: Provisioning with OpenTofu.
- SMTP: Email infrastructure with OpenTofu (Resend).
- DNS: Domain configuration with OpenTofu (Cloudflare), including automatic SMTP records.
- SMTP Post-Verification: Finalizing SMTP setup (e.g., domain verification) with OpenTofu.
- Remote Config: System configuration with Ansible on the remote host.
- Local Config: Finalizing setup with Ansible on the local machine.
- Multi-Cloud Support: Native templates for:
- Hetzner Cloud (
hcloud) - Oracle Cloud Infrastructure (
oci) - No-Infra (
no-infra): For when the server is already there.
- Hetzner Cloud (
- Dynamic Inventory: Automatically bridge the gap by generating Ansible inventory directly from OpenTofu outputs.
- SMTP Testing Ready: Automatically installs
s-nailand configures.mailrcon the remote host for immediate SMTP verification. - Environment Overrides: Support for overriding any configuration parameter via environment variables (e.g.,
BC_VAR_RESEND_PASSWORD). - Configurable Workflows: Execute complex multi-step processes like
tofu init/applyfollowed by multipleansible-playbookruns.
Prerequisites
Section titled “Prerequisites”To use once, you need the following tools installed:
- Clojure: The core engine.
- Babashka: Recommended for running CLI tasks.
- OpenTofu: For infrastructure management.
- Ansible: For configuration management.
- Cloud Credentials: e.g.,
HCLOUD_TOKEN,CLOUDFLARE_API_TOKEN,RESEND_API_KEY, or OCI configuration.
Configuration Overrides
Section titled “Configuration Overrides”You can override any parameter defined in options.clj using environment variables prefixed with BC_VAR_. The variable name is converted to lowercase, and underscores or dots are replaced with hyphens.
Example:
export BC_VAR_RESEND_PASSWORD="your-smtp-password"export BC_VAR_DOMAIN="example.com"These will be automatically merged into the workflow parameters.
Via Babashka (Recommended)
Section titled “Via Babashka (Recommended)”The easiest way to interact with once is through the provided Babashka tasks.
1. Setup
Section titled “1. Setup”Clone the repository and configure your options:
git clone https://github.com/amiorin/oncecd once# Edit your chosen provider optionsedit src/clj/io/github/amiorin/once/options.cljIn bb.edn, you can switch the active profile by changing the require statement:
;; bb.edn:requires [... ;; Switch between oci, hcloud, or no-infra [io.github.amiorin.once.options :refer [oci] :rename {oci options}] ...]2. Main Workflow
Section titled “2. Main Workflow”The once task handles the full lifecycle. You can pass multiple commands:
- Full Setup:
bb once create(Tofu -> Tofu SMTP -> Tofu DNS -> Tofu SMTP Post -> Ansible -> Ansible Local) - Tear Down:
bb once delete(Tofu DNS Destroy -> Tofu SMTP Post Destroy -> Tofu SMTP Destroy -> Tofu Destroy) - Sequential:
bb once delete create(Clean slate redeploy)
3. Targeted Tools
Section titled “3. Targeted Tools”You can also run the underlying tools individually. Most tasks require a render step first to generate the necessary config files from templates into the .dist/ directory.
- OpenTofu (Infrastructure):
Terminal window bb tofu render tofu:init tofu:apply:-auto-approve - OpenTofu (SMTP):
Terminal window bb tofu-smtp render tofu:init tofu:apply:-auto-approve - OpenTofu (DNS):
Terminal window bb tofu-dns render tofu:init tofu:apply:-auto-approve - OpenTofu (SMTP Post-Verification):
Terminal window bb tofu-smtp-post render tofu:init tofu:apply:-auto-approve - Remote Ansible:
Terminal window bb ansible render -- ansible-playbook main.yml - Local Ansible:
Terminal window bb ansible-local render -- ansible-playbook main.yml
Programmatic Usage
Section titled “Programmatic Usage”You can trigger workflows directly from a Clojure REPL:
(require '[io.github.amiorin.once.package :as once])(require '[io.github.amiorin.once.options :as options])
;; Run the "create" workflow using OCI profile(once/once* "create" options/oci)How It Works
Section titled “How It Works”- Template Rendering:
big-configtakes templates fromsrc/resourcesand your options to generate valid Tofu and Ansible files in.dist/. - Infrastructure Hook: When
createruns, it first executes OpenTofu to provision resources. - Inventory & Config Bridging: The Tofu output (like the new server IP or SMTP records) is captured using
tofu output --jsonand injected into the DNS configuration and Ansible inventory generation logic. - Configuration: Ansible then connects to the new host using the dynamically generated inventory to apply your playbooks.
Project Structure
Section titled “Project Structure”src/clj/.../once/:package.clj: Defines the high-levelcreate/deleteworkflows.params.clj: Logic for extracting parameters from Tofu outputs.tools.clj: Implementation details for Tofu, Tofu SMTP, Tofu DNS, and Ansible wrappers.options.clj: Where you define your cloud profiles and credentials.
src/resources/.../once/tools/:tofu/: Multi-cloud.tftemplates.tofu-smtp/: SMTP configuration templates (Resend).tofu-dns/: DNS configuration templates (Cloudflare).tofu-smtp-post/: SMTP post-verification templates (Resend).ansible/: Remote system playbooks.ansible-local/: Local machine configuration playbooks.
Development
Section titled “Development”If you are contributing to once, you can use the following task to keep the code clean:
bb tidyThis uses clojure-lsp to clean namespaces and format the source code.
License
Section titled “License”Copyright © 2026 Alberto Miorin
Distributed under the MIT License.