How to Let Claude Code Deploy Your Ghost Blog (DNS, VPS, and Ghost API)

A step-by-step guide to letting Claude Code autonomously configure Cloudflare DNS, set up a Hetzner VPS over SSH, deploy Ghost with Traefik, and initialize the blog via the Ghost Admin API — with honest notes on what still needs a human.

How to Let Claude Code Deploy Your Ghost Blog (DNS, VPS, and Ghost API)
Also available in Deutsch, Français, Español, Nederlands.

You have a domain. You have a Hetzner account. You want Ghost running on your own server with HTTPS, Cloudflare in front, and a MySQL database behind it. The manual path takes two hours: create the server, SSH in, configure Docker Compose, fight Let's Encrypt, debug Traefik, initialise Ghost through a browser form.

There is another path. Hand the job to Claude Code. Give it your credentials and a task description, and it will configure Cloudflare DNS, deploy the stack over SSH, and initialise Ghost via the Admin API without you touching a terminal. This is how clawstack.run was set up.

This post documents exactly what Claude can do on its own, what still requires a human click, and how to structure the handoff so it works first time.


What Claude Code Can and Cannot Do

Claude Code has access to your filesystem, a terminal, and any API you point it at. That covers most of this deployment. But some things still live behind browser UIs with no API equivalent.

Claude handles autonomously: - Creating Cloudflare DNS A records via API - Generating .env files and Docker Compose configs - SSHing into the server and running commands - Uploading deployment files - Starting Docker containers - Initialising Ghost via the Admin API (creating the admin account, first post, site title) - Debugging failures by reading logs and making corrections

You must do manually (one-time clicks): - Creating the Hetzner server (no Hetzner API key in scope — or you can add one and Claude handles this too) - Setting Cloudflare SSL/TLS mode to Full (Strict) in the dashboard - Retrieving the Ghost Admin API key from the Ghost admin UI after first login

Everything else is automatable. The two manual steps take under five minutes combined.


What You Need Before Starting

  • A domain with DNS managed at Cloudflare
  • A Cloudflare API token with Zone / DNS / Edit permission, scoped to your domain
  • A Hetzner account (or any VPS provider — adjust the IP below)
  • An SSH password or key for the server
  • Claude Code running locally with filesystem and Bash access

The SSH authentication method doesn't matter. Claude Code will use whatever you have — key file or password via sshpass. If you're using a password, install sshpass first:

sudo apt install sshpass

Step 1 — Create the Server

Go to the Hetzner Cloud Console and create a new server: - Type: CX22 (2 vCPU, 4 GB RAM) — enough for Ghost + MySQL + Traefik - Image: Ubuntu 24.04 - Region: your closest one - SSH key or password: your choice

In the "Cloud config" field, paste your cloud-init.yaml. This installs Docker, creates the deploy user, configures UFW, and sets up fail2ban in one shot. You can use the one from clawstack-configs on GitHub as a starting point.

Note the server's IP address. That's the last thing you need to do manually.


Step 2 — Give Claude Code the Context

Create a CLAUDE.md file in your project directory. This is the brief Claude reads at the start of every session. Include:

# Deployment Context

## Server
- IP: 203.0.113.42
- SSH user: deploy
- SSH auth: password via sshpass / key at ~/.ssh/mykey

## Domain
- Domain: yourdomain.com
- DNS: Cloudflare (token in .env as CLOUDFLARE_TOKEN)

## Stack
- Ghost 5 + MySQL 8 + Traefik (Docker Compose)
- Compose file: deploy/docker-compose.yml
- Deploy directory on server: /opt/ghost

## Credentials
- All secrets in deploy/.env (never commit)

Then create deploy/.env with your actual values:

DOMAIN=yourdomain.com
ACME_EMAIL=you@yourdomain.com
CLOUDFLARE_TOKEN=your_cloudflare_dns_token

DB_NAME=ghost
DB_USER=ghost
DB_PASSWORD=generate_with_openssl_rand_base64_32
DB_ROOT_PASSWORD=generate_with_openssl_rand_base64_32

MAIL_HOST=smtp.fastmail.com
MAIL_PORT=587
MAIL_USER=you@fastmail.com
MAIL_PASS=your_app_password
MAIL_FROM=noreply@yourdomain.com

Generate the DB passwords locally:

openssl rand -base64 32

Step 3 — Configure DNS

Give Claude Code this prompt:

Using the Cloudflare API token in deploy/.env, create the following DNS records
for the domain in .env:
- A record: @ → the server IP in CLAUDE.md
- A record: www → the server IP in CLAUDE.md
- A record: * → the server IP in CLAUDE.md

Use the Cloudflare API at https://api.cloudflare.com/client/v4.
First get the zone ID for the domain, then create each record.
Check for existing records and skip or update as needed.

Claude will call the Cloudflare API, get the zone ID, create the records, and confirm each one. The whole thing takes about thirty seconds.

If you have email records (MX, DKIM, SPF) from a provider like FastMail, tell Claude those too. It can create them in the same pass.

After DNS propagation (usually under five minutes with Cloudflare), set the SSL/TLS mode manually:

Cloudflare Dashboard → yourdomain.com → SSL/TLS → Overview → Full (Strict)

This is the one click that cannot be automated with a scoped DNS token.


Step 4 — Deploy the Stack

Once DNS is up and the server is running, give Claude the deployment prompt:

Deploy the Ghost stack to the server documented in CLAUDE.md.

1. Upload deploy/docker-compose.yml and deploy/.env to /opt/ghost on the server
2. SSH in and create the traefik/ directory with an empty acme.json (chmod 600)
3. Run: docker compose up -d
4. Wait 30 seconds, then check: docker compose ps
5. Check Ghost logs for any startup errors: docker compose logs --tail=50 ghost
6. If everything looks healthy, report the container statuses

Claude will SSH in, upload the files, start the containers, and read the logs. If something goes wrong — and the first deploy often has a small issue — Claude will diagnose it and apply the fix. The five most common failures are documented in Ghost Behind Cloudflare and Traefik: The Complete Working Setup.

The most likely ones: missing @docker suffix on Traefik middleware references, wrong Cloudflare token variable name, or the Docker network name prefix not matching the compose project directory name.


Step 5 — Initialise Ghost via the Admin API

Ghost ships with a one-time setup endpoint. Until you call it, the blog is in "uninitialised" state — no admin account exists. You can do this through the browser at /ghost, or let Claude do it via API.

Give Claude this prompt:

Initialise Ghost at https://yourdomain.com using the Admin API setup endpoint.
Create an admin account with:
- name: Admin
- email: you@yourdomain.com
- password: (generate a strong one and tell me what it is)
- blogTitle: Your Blog Title

POST to: https://yourdomain.com/ghost/api/admin/authentication/setup
Check the response for success and report the result.

Claude will call the endpoint and return the confirmation. The response includes a user object — the admin account is live.

# What Claude runs under the hood:
curl -s -X POST https://yourdomain.com/ghost/api/admin/authentication/setup \
  -H "Content-Type: application/json" \
  -d '{
    "setup": [{
      "name": "Admin",
      "email": "you@yourdomain.com",
      "password": "YourPassword123!",
      "blogTitle": "Your Blog Title"
    }]
  }'

If the endpoint returns a 403, Ghost is already initialised (someone got there first — possibly you testing the URL in a browser). If it returns a connection error, the containers aren't up yet.


Step 6 — Get the Admin API Key

Log into Ghost admin at https://yourdomain.com/ghost with the credentials Claude just created.

Go to: Settings → Integrations → Add custom integration

Name it anything — "Automation" works. Ghost will show you an Admin API key in id:hexsecret format. Save it to deploy/.env as GHOST_ADMIN_KEY.

From this point, Claude can create posts, upload images, manage tags, and publish drafts entirely through the API — no browser required.


Verifying the Setup

Once everything is deployed, ask Claude to run the verification checklist:

Run the following checks and report the HTTP status code for each:

1. curl -s https://yourdomain.com/ -o /dev/null -w "%{http_code}"   → should be 200
2. curl -s https://www.yourdomain.com/ -o /dev/null -w "%{http_code}"  → should be 301
3. curl -s http://yourdomain.com/ -o /dev/null -w "%{http_code}"    → should be 301
4. curl -sv https://yourdomain.com/ 2>&1 | grep issuer   → should say Let's Encrypt

Also check:
5. docker compose ps   → all containers should be Up
6. docker compose logs traefik | grep -i error   → should be empty

If step 1 returns 000 or hangs, there is a Traefik routing issue. If it returns 301, the Ghost redirect loop is active — see the Traefik post for the fix. If step 4 shows a Cloudflare certificate instead of Let's Encrypt, DNS-01 challenge hasn't completed yet or the CLOUDFLARE_TOKEN variable is named wrong.


The Full Prompt for a Clean Server

If you want to hand the entire job to Claude in one go — DNS, deploy, and Ghost initialisation — here is the prompt. Assumes CLAUDE.md is written and .env is ready:

Deploy Ghost to the server documented in CLAUDE.md. Do the following in order:

1. Use the Cloudflare API to create A records for @, www, and * pointing to the server IP.
   Check for existing records first; update if present, create if not.

2. Upload deploy/docker-compose.yml and deploy/.env to /opt/ghost on the server.
   Create /opt/ghost/traefik/acme.json with chmod 600.

3. SSH in and run: docker compose up -d
   Wait 45 seconds, then check docker compose ps and docker compose logs ghost.
   Fix any startup errors before continuing.

4. Once all containers are healthy, initialise Ghost via POST to
   /ghost/api/admin/authentication/setup with the credentials below.
   Tell me the password you generate.

5. Confirm the site returns HTTP 200 at https://[DOMAIN]/.
   Report any failures with the relevant log output.

Admin credentials to create:
- email: you@yourdomain.com
- blogTitle: Your Blog Title

Claude will work through the list, report status after each step, and stop to ask if something requires a decision. On a clean server with correct credentials, the whole deployment takes about four minutes.


Using an AI to Debug the Deployment

If something breaks during a deployment Claude is running, the fastest path is to paste both this post and the Ghost + Traefik + Cloudflare bugs post into the conversation. Together they cover every failure mode we've hit. Claude will cross-reference the error in the logs against the documented patterns and tell you exactly which label is wrong or which environment variable is missing.


Where to Run This

Hetzner CX22 is the machine this runs on. €4.85/month, two vCPUs, 4 GB RAM. The deploy user has no password by default — cloud-init locks it — so Claude authenticates by key or the temporary password you set during server creation.

If the goal is an AI assistant that can manage the server autonomously after setup — restart containers, create posts, monitor logs — xCloud hosts OpenClaw managed. You get the same autonomous operations without maintaining the server yourself. The deployment described in this post is what xCloud is running under the hood.

(Affiliate links — we get a small cut if you sign up, at no cost to you.)


Resources


German Version (Deutsch)


Metadaten

  • Titel: Ghost mit Claude Code deployen: DNS, VPS und Ghost API automatisiert
  • Slug: claude-code-ghost-deployment-de
  • Beschreibung: Schritt-für-Schritt-Anleitung, um Claude Code Cloudflare DNS konfigurieren, einen Hetzner VPS per SSH einrichten, Ghost mit Traefik deployen und den Blog über die Ghost Admin API initialisieren zu lassen — mit ehrlichen Hinweisen, was noch ein Mensch tun muss.
  • Tags: claude-code, ghost, cloudflare, hetzner, docker, automation, selbst-gehostet, infra
  • Pillar: /openclaw/
  • Language: de
  • Reading Time: 10 min

Inhalt

Du hast eine Domain. Du hast einen Hetzner-Account. Du willst Ghost auf deinem eigenen Server mit HTTPS, Cloudflare davor und einer MySQL-Datenbank dahinter. Der manuelle Weg dauert zwei Stunden: Server erstellen, per SSH einloggen, Docker Compose konfigurieren, mit Let's Encrypt kämpfen, Traefik debuggen, Ghost durch ein Browser-Formular initialisieren.

Es gibt einen anderen Weg. Übergib den Job an Claude Code. Gib ihm deine Zugangsdaten und eine Aufgabenbeschreibung — es konfiguriert Cloudflare DNS, deployt den Stack per SSH und initialisiert Ghost über die Admin API, ohne dass du ein Terminal anfassen musst. So wurde clawstack.run aufgesetzt.

Dieser Post dokumentiert genau, was Claude eigenständig tun kann, was noch einen menschlichen Klick erfordert, und wie du die Übergabe strukturierst, damit es beim ersten Versuch funktioniert.


Was Claude Code kann und was nicht

Claude Code hat Zugriff auf dein Dateisystem, ein Terminal und jede API, auf die du es hinweist. Das deckt den Großteil dieses Deployments ab. Einige Dinge befinden sich aber noch hinter Browser-UIs ohne API-Äquivalent.

Claude erledigt selbstständig: - Cloudflare DNS A-Records per API anlegen - .env-Dateien und Docker Compose Configs erstellen - Per SSH auf den Server zugreifen und Befehle ausführen - Deployment-Dateien hochladen - Docker Container starten - Ghost per Admin API initialisieren (Admin-Account, erster Post, Seitentitel) - Fehler durch Log-Analyse diagnostizieren und beheben

Manuelle Schritte (einmalige Klicks): - Hetzner Server erstellen (oder Hetzner API Key bereitstellen, dann kann Claude das auch) - Cloudflare SSL/TLS-Modus auf Full (Strict) setzen im Dashboard - Ghost Admin API Key aus dem Ghost Admin UI auslesen nach dem ersten Login

Alles andere ist automatisierbar. Die zwei manuellen Schritte dauern zusammen unter fünf Minuten.


Voraussetzungen

  • Eine Domain mit DNS bei Cloudflare
  • Ein Cloudflare API Token mit Zone / DNS / Edit-Berechtigung, auf deine Domain beschränkt
  • Ein Hetzner-Account (oder anderer VPS-Anbieter — IP unten anpassen)
  • SSH-Passwort oder Key für den Server
  • Claude Code lokal mit Dateisystem- und Bash-Zugriff

Die SSH-Authentifizierungsmethode spielt keine Rolle. Claude Code verwendet was du hast — Key-Datei oder Passwort via sshpass. Bei Passwort-Authentifizierung zuerst installieren:

sudo apt install sshpass

Schritt 1 — Server erstellen

In der Hetzner Cloud Console einen neuen Server anlegen: - Typ: CX22 (2 vCPU, 4 GB RAM) — reicht für Ghost + MySQL + Traefik - Image: Ubuntu 24.04 - Region: nächstgelegene - SSH Key oder Passwort: nach Wahl

Im Feld "Cloud config" das cloud-init.yaml einfügen. Das installiert Docker, legt den Deploy-User an, konfiguriert UFW und richtet fail2ban ein. Als Ausgangspunkt eignet sich die Datei aus clawstack-configs auf GitHub.

Die IP-Adresse des Servers notieren. Das ist die letzte manuelle Aktion.


Schritt 2 — Claude Code den Kontext geben

Eine CLAUDE.md-Datei im Projektverzeichnis anlegen. Das ist das Briefing, das Claude zu Beginn jeder Session liest:

# Deployment Context

## Server
- IP: 203.0.113.42
- SSH-User: deploy
- SSH-Auth: Passwort via sshpass / Key unter ~/.ssh/mykey

## Domain
- Domain: yourdomain.com
- DNS: Cloudflare (Token in .env als CLOUDFLARE_TOKEN)

## Stack
- Ghost 5 + MySQL 8 + Traefik (Docker Compose)
- Compose-Datei: deploy/docker-compose.yml
- Deploy-Verzeichnis auf Server: /opt/ghost

## Zugangsdaten
- Alle Secrets in deploy/.env (nie committen)

Dann deploy/.env mit den echten Werten anlegen:

DOMAIN=yourdomain.com
ACME_EMAIL=du@yourdomain.com
CLOUDFLARE_TOKEN=dein_cloudflare_dns_token

DB_NAME=ghost
DB_USER=ghost
DB_PASSWORD=mit_openssl_rand_base64_32_generieren
DB_ROOT_PASSWORD=mit_openssl_rand_base64_32_generieren

MAIL_HOST=smtp.fastmail.com
MAIL_PORT=587
MAIL_USER=du@fastmail.com
MAIL_PASS=dein_app_passwort
MAIL_FROM=noreply@yourdomain.com

DB-Passwörter lokal generieren:

openssl rand -base64 32

Schritt 3 — DNS konfigurieren

Claude Code diesen Prompt geben:

Lege mit dem Cloudflare API Token aus deploy/.env folgende DNS-Records
für die Domain in .env an:
- A-Record: @ → Server-IP aus CLAUDE.md
- A-Record: www → Server-IP aus CLAUDE.md
- A-Record: * → Server-IP aus CLAUDE.md

Cloudflare API: https://api.cloudflare.com/client/v4
Zuerst die Zone-ID für die Domain abrufen, dann jeden Record anlegen.
Vorhandene Records prüfen und ggf. aktualisieren statt doppelt anlegen.

Claude ruft die Cloudflare API auf, ermittelt die Zone-ID, legt die Records an und bestätigt jeden einzelnen. Das dauert etwa dreißig Sekunden.

Nach DNS-Propagation (mit Cloudflare meist unter fünf Minuten) den SSL-Modus manuell setzen:

Cloudflare Dashboard → yourdomain.com → SSL/TLS → Übersicht → Full (Strict)

Das ist der eine Klick, der mit einem beschränkten DNS-Token nicht automatisierbar ist.


Schritt 4 — Stack deployen

Wenn DNS aktiv und der Server bereit ist:

Deploye den Ghost-Stack auf den in CLAUDE.md dokumentierten Server.

1. deploy/docker-compose.yml und deploy/.env nach /opt/ghost hochladen
2. Per SSH einloggen und /opt/ghost/traefik/acme.json anlegen (chmod 600)
3. docker compose up -d ausführen
4. 30 Sekunden warten, dann docker compose ps prüfen
5. Ghost-Logs auf Startfehler prüfen: docker compose logs --tail=50 ghost
6. Bei gesundem Status alle Container-Zustände melden

Claude loggt per SSH ein, lädt die Dateien hoch, startet die Container und liest die Logs. Wenn etwas schiefläuft — beim ersten Deploy oft eine Kleinigkeit — diagnostiziert Claude es und behebt es. Die fünf häufigsten Fehler sind in Ghost hinter Cloudflare und Traefik dokumentiert.


Schritt 5 — Ghost per Admin API initialisieren

Ghost hat einen einmaligen Setup-Endpoint. Bis er aufgerufen wird, existiert kein Admin-Account. Das geht über den Browser unter /ghost oder per API:

Initialisiere Ghost unter https://yourdomain.com über den Admin API Setup-Endpoint.
Admin-Account erstellen:
- name: Admin
- email: du@yourdomain.com
- password: (generiere ein starkes Passwort und teile es mir mit)
- blogTitle: Dein Blog-Titel

POST an: https://yourdomain.com/ghost/api/admin/authentication/setup
Antwort auf Erfolg prüfen und melden.
# Was Claude im Hintergrund ausführt:
curl -s -X POST https://yourdomain.com/ghost/api/admin/authentication/setup \
  -H "Content-Type: application/json" \
  -d '{
    "setup": [{
      "name": "Admin",
      "email": "du@yourdomain.com",
      "password": "DeinPasswort123!",
      "blogTitle": "Dein Blog-Titel"
    }]
  }'

Bei 403: Ghost ist bereits initialisiert. Bei Connection Error: Container laufen noch nicht.


Schritt 6 — Admin API Key auslesen

Im Ghost Admin unter https://yourdomain.com/ghost einloggen.

Einstellungen → Integrationen → Eigene Integration hinzufügen

Den Admin API Key im Format id:hexsecret in deploy/.env als GHOST_ADMIN_KEY speichern.

Ab jetzt kann Claude Beiträge erstellen, Bilder hochladen, Tags verwalten und Entwürfe veröffentlichen — ohne Browser.


Setup verifizieren

Folgende Checks ausführen und HTTP-Statuscodes melden:

1. curl -s https://yourdomain.com/ -o /dev/null -w "%{http_code}"        → 200 erwartet
2. curl -s https://www.yourdomain.com/ -o /dev/null -w "%{http_code}"    → 301 erwartet
3. curl -s http://yourdomain.com/ -o /dev/null -w "%{http_code}"         → 301 erwartet
4. curl -sv https://yourdomain.com/ 2>&1 | grep issuer                   → Let's Encrypt erwartet

Außerdem:
5. docker compose ps   → alle Container Up
6. docker compose logs traefik | grep -i error   → leer erwartet

Der vollständige Prompt für einen sauberen Server

Deploye Ghost auf den in CLAUDE.md dokumentierten Server. In dieser Reihenfolge:

1. Cloudflare API: A-Records für @, www und * auf die Server-IP setzen.
   Vorhandene Records prüfen; aktualisieren wenn vorhanden, anlegen wenn nicht.

2. deploy/docker-compose.yml und deploy/.env nach /opt/ghost hochladen.
   /opt/ghost/traefik/acme.json anlegen mit chmod 600.

3. Per SSH: docker compose up -d
   45 Sekunden warten, dann docker compose ps und docker compose logs ghost prüfen.
   Startfehler beheben bevor weiter.

4. Nach gesundem Start Ghost per POST an
   /ghost/api/admin/authentication/setup initialisieren.
   Generiertes Passwort mitteilen.

5. Bestätigen dass https://[DOMAIN]/ HTTP 200 zurückgibt.
   Bei Fehlern: relevante Log-Ausgabe melden.

Admin-Zugangsdaten:
- email: du@yourdomain.com
- blogTitle: Dein Blog-Titel

Bei korrekten Zugangsdaten dauert das komplette Deployment auf einem sauberen Server etwa vier Minuten.


KI zum Debuggen einsetzen

Wenn während eines Deployments etwas schiefläuft, füge diesen Post und den Ghost + Traefik + Cloudflare Bugs Post in die Konversation ein. Zusammen decken sie jeden Fehler ab, auf den ich gestoßen bin. Claude gleicht den Fehler in den Logs mit den dokumentierten Mustern ab und sagt dir genau, welches Label falsch ist oder welche Umgebungsvariable fehlt.


Wo das läuft

Hetzner CX22 — €4,85/Monat, zwei vCPUs, 4 GB RAM. Der Deploy-User hat standardmäßig kein Passwort — cloud-init sperrt es — Claude authentifiziert sich per Key oder temporärem Passwort aus der Server-Erstellung.

Wer einen KI-Assistenten will, der den Server nach dem Setup eigenständig verwalten kann — Container neu starten, Beiträge erstellen, Logs überwachen — xCloud hostet OpenClaw managed. Was in diesem Post beschrieben ist, läuft bei xCloud unter der Haube.

(Affiliate-Links — ich bekomme eine kleine Provision, wenn du dich anmeldest, ohne Mehrkosten für dich.)


Ressourcen


Publishing Notes

SEO keywords targeted: - "Claude Code deploy Ghost" - "automate Ghost deployment" - "Ghost VPS setup automated" - "Cloudflare DNS API automation" - "Ghost Admin API setup endpoint" - (DE) "Ghost automatisch deployen" - (DE) "Claude Code Ghost einrichten"

Internal links: - Links to post 02 (Ghost + Traefik + Cloudflare bugs) in two places - References clawstack-configs GitHub repo (to be created)

Note: cloud-init.yaml in this repo contains root@stadicus.com in the SSH key comment — strip before publishing or replace with neutral key comment.