<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Operations on OpenClaw Deploy</title><link>http://tardigrde.github.io/openclaw-deploy/operations/</link><description>Recent content in Operations on OpenClaw Deploy</description><generator>Hugo</generator><language>en</language><atom:link href="http://tardigrde.github.io/openclaw-deploy/operations/index.xml" rel="self" type="application/rss+xml"/><item><title>Backup &amp; Restore</title><link>http://tardigrde.github.io/openclaw-deploy/operations/backup-restore/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://tardigrde.github.io/openclaw-deploy/operations/backup-restore/</guid><description>&lt;p&gt;Backups run daily at &lt;strong&gt;03:00 UTC&lt;/strong&gt; via systemd timer and are stored in &lt;code&gt;~/backups/&lt;/code&gt; on the VPS.&lt;/p&gt;
&lt;h2 id="make-targets"&gt;Make Targets&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make backup-now &lt;span style="color:#75715e"&gt;# Trigger backup immediately&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make backup-pull &lt;span style="color:#75715e"&gt;# Download latest backup archive locally&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make restore &lt;span style="color:#75715e"&gt;# List available backups (dry-run — safe)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make restore EXECUTE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; BACKUP&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;lt;file&amp;gt; &lt;span style="color:#75715e"&gt;# Restore from backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;make restore&lt;/code&gt; without &lt;code&gt;EXECUTE=1&lt;/code&gt; is always safe — it just lists available backups.&lt;/p&gt;</description></item><item><title>CI/CD Setup</title><link>http://tardigrde.github.io/openclaw-deploy/operations/cicd/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://tardigrde.github.io/openclaw-deploy/operations/cicd/</guid><description>&lt;h1 id="cicd"&gt;CI/CD&lt;/h1&gt;
&lt;p&gt;The built-in CI &lt;strong&gt;validates and tests&lt;/strong&gt; Terraform (&lt;code&gt;terraform fmt&lt;/code&gt;, &lt;code&gt;terraform validate&lt;/code&gt;, &lt;code&gt;tflint&lt;/code&gt;, &lt;code&gt;terraform test&lt;/code&gt;). Ansible is never run in CI — all &lt;code&gt;make bootstrap&lt;/code&gt; / &lt;code&gt;make deploy&lt;/code&gt; operations are local only.&lt;/p&gt;
&lt;p&gt;Example workflows for &lt;code&gt;terraform plan&lt;/code&gt; (on PRs) and &lt;code&gt;terraform apply&lt;/code&gt; (manual dispatch) are included as &lt;code&gt;.example.yml&lt;/code&gt; files — copy them to enable (see &lt;a href="#required-github-secrets"&gt;Required Secrets&lt;/a&gt; below).&lt;/p&gt;
&lt;p&gt;An optional GitOps deployment workflow is also included — copy &lt;code&gt;.github/workflows/deploy.yml.example&lt;/code&gt; to &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt; to enable automatic Ansible-based deployments on push. See &lt;a href="http://tardigrde.github.io/openclaw-deploy/operations/gitops-auto-deploy/"&gt;GitOps auto-deploy&lt;/a&gt; for setup instructions.&lt;/p&gt;</description></item><item><title>GitOps Auto-Deploy</title><link>http://tardigrde.github.io/openclaw-deploy/operations/gitops-auto-deploy/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://tardigrde.github.io/openclaw-deploy/operations/gitops-auto-deploy/</guid><description>&lt;h1 id="gitops-auto-deploy"&gt;GitOps Auto-Deploy&lt;/h1&gt;
&lt;p&gt;A GitHub Actions pipeline can automatically deploy to the VPS on every push to &lt;code&gt;main&lt;/code&gt;. This is &lt;strong&gt;optional&lt;/strong&gt; — if you don&amp;rsquo;t configure the secrets below, the workflow won&amp;rsquo;t run and you can continue deploying manually with &lt;code&gt;make deploy&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="what-it-does"&gt;What It Does&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Triggered by changes to &lt;code&gt;openclaw.json&lt;/code&gt;, &lt;code&gt;docker/&lt;/code&gt;, &lt;code&gt;docker-compose.yml&lt;/code&gt;, &lt;code&gt;ansible/&lt;/code&gt;, or &lt;code&gt;secrets/.env.enc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Connects to the VPS via an ephemeral Tailscale node (no public SSH required)&lt;/li&gt;
&lt;li&gt;Decrypts &lt;code&gt;secrets/.env.enc&lt;/code&gt; using SOPS + age key from GitHub Secrets&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;docker/&lt;/code&gt; or &lt;code&gt;docker-compose.yml&lt;/code&gt; changed: runs &lt;code&gt;make deploy REBUILD=1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Otherwise: runs &lt;code&gt;make deploy&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A manual &lt;strong&gt;rollback workflow&lt;/strong&gt; is also included (&lt;code&gt;.github/workflows/rollback.yml&lt;/code&gt;) — trigger it from the GitHub Actions UI with any previous git SHA. It also decrypts secrets with SOPS before deploying.&lt;/p&gt;</description></item><item><title>Remote State</title><link>http://tardigrde.github.io/openclaw-deploy/operations/remote-state/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://tardigrde.github.io/openclaw-deploy/operations/remote-state/</guid><description>&lt;h1 id="remote-state-backend"&gt;Remote State Backend&lt;/h1&gt;
&lt;p&gt;By default Terraform uses a &lt;strong&gt;local backend&lt;/strong&gt; (&lt;code&gt;terraform.tfstate&lt;/code&gt; on disk). This requires zero setup and works fine for solo use. For team workflows or CI/CD, a remote backend gives you shared state, versioning, and locking.&lt;/p&gt;
&lt;h2 id="choosing-a-backend"&gt;Choosing a Backend&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;terraform/envs/prod/backend.tf&lt;/code&gt; (copied from &lt;code&gt;backend.tf.example&lt;/code&gt;) controls the backend:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 6
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 7
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 8
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 9
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;10
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;11
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-hcl" data-lang="hcl"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Option A — Local (default, no setup required)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;terraform&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;backend&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;local&amp;#34;&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Option B — GCS (recommended for teams / CI)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;terraform&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;backend&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;gcs&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bucket &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;your-project-tfstate&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; prefix &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;openclaw/prod&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Terraform supports other backends too (S3, Azure Blob, Terraform Cloud). Any Terraform-compatible backend works — update &lt;code&gt;backend.tf&lt;/code&gt; accordingly. Note that S3 requires a separate DynamoDB table for state locking, whereas GCS locks natively.&lt;/p&gt;</description></item></channel></rss>