I recently deployed my Hugo blog to Namecheap shared hosting, using Obsidian as my content editor and Claude Code with PAI (Personal AI) as my copilot. Here’s a walkthrough of every step, from fixing build errors to setting up a fully automated pipeline that goes from Obsidian to live site in a single command.

The Starting Point

I created a Hugo blog project called Augmented Resilience and used the re-terminal theme, a Namecheap shared hosting account, and a GitHub repository. I used Claude Code in VS Code editor and leveraged Daniel Miessler’s Personal AI infrastructure. The goal: get the site live at augmentedresilience.com with a push-to-deploy workflow.

For context, the Personal AI Infrastructure System (PAI) from Daniel Miessler (see resources below) is an open-source framework that wraps around Claude Code and turns it into a structured problem-solving system. Instead of just chatting with an AI, PAI runs every request through a 7-phase algorithm — observe, think, plan, build, execute, verify, learn — so nothing gets skipped. It maintains persistent memory across sessions (so it remembers my project structure, preferences, and past decisions), automatically selects specialized agents for different tasks (security review, architecture, engineering), and enforces verification criteria before declaring anything “done.” For this project, PAI handled everything from debugging Hugo build errors to writing the deploy script to catching sensitive data I accidentally left in this blog post before it went live. It wasn’t just an AI assistant — it was the entire workflow engine. I found it easier to use it within VS Code (still getting used to using the command line interface).

Step 1: Fixing the Hugo Build

The first issue was a build error:

module "hugo-theme-re-terminal" not found

The problem was a mismatch between the theme name in hugo.toml and the actual directory name. The theme was installed as a git submodule at themes/re-terminal/, but the config referenced hugo-theme-re-terminal.

Fix: Change the theme name in hugo.toml:

theme = "re-terminal"

After that, hugo built the site successfully, generating the public/ folder with all the static files.

Step 2: Setting Up the GitHub Repository

I initialized the repo and connected it to GitHub:

git init
git remote add origin git@github.com:dsacosta/Augmented-Resilience.git
git add .
git commit -m "my first commit"
git push origin main

One gotcha: I initially typed orgin instead of origin in the remote add command. Typos happen — double-check your remote names with git remote -v.

Step 3: Connecting Namecheap to GitHub via SSH

This was the trickiest part. Namecheap shared hosting needs an SSH key to clone from a private GitHub repo. Here’s what worked:

Generate an SSH Key on Namecheap

  1. Log into cPanel on Namecheap
  2. Go to SSH AccessManage SSH KeysGenerate a New Key
  3. Generate an RSA key (I used the default settings)

Remove the Passphrase

This is critical. cPanel’s Git Version Control runs non-interactively, so it can’t prompt for a passphrase. I opened cPanel Terminal and ran:

ssh-keygen -p -f ~/.ssh/id_rsa

Enter the old passphrase, then press Enter twice for no new passphrase.

Add the Public Key to GitHub

  1. On Namecheap’s cPanel Terminal, run: cat ~/.ssh/id_rsa.pub
  2. Copy the output
  3. Go to your GitHub repo → SettingsDeploy KeysAdd deploy key
  4. Paste the public key and save

Verify the Connection

From cPanel Terminal:

ssh -T git@github.com

You should see: Hi dsacosta/Augmented-Resilience! You've successfully authenticated...

Step 4: Clone the Repo on Namecheap

  1. In cPanel, go to Git Version ControlCreate
  2. Toggle Clone a Repository on
  3. Enter the clone URL: git@github.com:dsacosta/Augmented-Resilience.git
  4. Set the repository path (I used /home/yourusername/your-repo)
  5. Click Create

Important: Don’t clone directly into public_html or your domain folder — it likely already has files and will error out. Clone to a separate directory and use deployment to copy files over.

Step 5: Auto-Deployment with .cpanel.yml

cPanel supports automatic deployment tasks via a .cpanel.yml file in the repo root. This file tells cPanel what to do after each pull:

---
deployment:
  tasks:
    - export DEPLOYPATH=/home/yourusername/yourdomain.com/
    - /bin/cp -R public/* $DEPLOYPATH

This copies everything from the public/ folder (Hugo’s build output) into the live site directory.

After pushing this file to GitHub:

  1. Go to Git Version ControlManage your repo
  2. Click the Pull or Deploy tab
  3. Click Update from Remote to pull the latest
  4. Click Deploy HEAD Commit to trigger the .cpanel.yml tasks

Your site should now be live.

Step 6: Fully Automated Deploys with GitHub Actions

To eliminate the manual “pull and deploy” step in cPanel, I set up a GitHub Actions workflow that SSHs into Namecheap and triggers the pull automatically on every push.

Generate a Deploy Key

On your local machine, generate a key pair with no passphrase:

ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/deploy_key -N ""

Add the public key to Namecheap:

# In cPanel Terminal on Namecheap:
echo "ssh-ed25519 AAAA...your-key-here github-actions-deploy" >> ~/.ssh/authorized_keys

Add Secrets to GitHub

Go to your repo → SettingsSecrets and variablesActions and add:

Secret Value
NC_HOST augmentedresilience.com
NC_USER Your cPanel username
NC_PORT Your SSH port (check cPanel)
NC_SSH_KEY The full private key (including BEGIN/END lines)

Create the Workflow

Add .github/workflows/deploy.yml to your repo:

name: Deploy to Namecheap

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy via SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.NC_HOST }}
          username: ${{ secrets.NC_USER }}
          key: ${{ secrets.NC_SSH_KEY }}
          port: ${{ secrets.NC_PORT }}
          script: |
            cd ~/your-repo && git pull origin main && /bin/cp -R public/* ~/yourdomain.com/

Now every push to main automatically deploys to your live site.

Step 7: One-Command Deploy Script

Five manual commands every time you publish? That’s not a workflow — that’s a chore. I had Claude write a Python script that handles everything in one shot:

#!/usr/bin/env python3
"""One-command deploy: Obsidian → Hugo → GitHub → Live site."""

import subprocess
import sys
from datetime import datetime

PROJECT_DIR = "~/Documents/Augmented-Resilience"
OBSIDIAN_POSTS = "~/projects/obsidian-vault/30-projects/augmented-resilience-posts"
HUGO_POSTS = f"{PROJECT_DIR}/content/posts"


def run(cmd, description, cwd=PROJECT_DIR):
    """Run a command and print status."""
    print(f"\n{'='*50}")
    print(f"  {description}")
    print(f"{'='*50}")
    result = subprocess.run(cmd, shell=True, cwd=cwd)
    if result.returncode != 0:
        print(f"\n  FAILED: {description}")
        sys.exit(1)
    return result


def main():
    msg = " ".join(sys.argv[1:]) if len(sys.argv) > 1 else f"Site update {datetime.now().strftime('%Y-%m-%d %H:%M')}"

    run(f'rsync -av --delete "{OBSIDIAN_POSTS}" "{HUGO_POSTS}"', "Syncing posts from Obsidian")
    run(f"python3 {PROJECT_DIR}/images.py", "Processing images")
    run("hugo", "Building site with Hugo")
    run("git add .", "Staging changes")

    result = subprocess.run("git diff --cached --quiet", shell=True, cwd=PROJECT_DIR)
    if result.returncode == 0:
        print("\n  No changes to commit. Site is up to date.")
        return

    run(f'git commit -m "{msg}"', "Committing")
    run("git push origin main", "Pushing to GitHub")

    print(f"\n{'='*50}")
    print("  DEPLOYED! Your site will be live shortly.")
    print(f"{'='*50}\n")


if __name__ == "__main__":
    main()

Save this as deploy.py in your project root. Now the entire workflow is:

# Default timestamped commit message
python3 deploy.py

# Or with a custom message
python3 deploy.py "Add new blog post about deployment"

The script runs every step in sequence — syncs from Obsidian, converts image links, builds with Hugo, commits, and pushes. If any step fails, it stops immediately so you don’t push a broken build. Combined with the GitHub Actions workflow from Step 6, pushing triggers the auto-deploy to Namecheap. One command, fully live.

Lessons Learned

  • SSH passphrases break cPanel automation. Always remove the passphrase from keys used by cPanel’s Git Version Control.
  • Theme names must match directory names. Hugo looks for the theme in themes/<theme-name>/, so the theme value in your config must match exactly.
  • Don’t clone into the live site directory. Clone to a separate folder and use .cpanel.yml to copy the built files over.
  • GitHub Actions + SSH is the cleanest auto-deploy for shared hosting. No webhooks, no cron jobs — just a simple SSH action that runs on every push.
  • Claude Code with PAI made this possible in a single session. From debugging build errors to SSH key troubleshooting to writing GitHub Actions workflows, having an AI pair programmer turned what could have been hours of Stack Overflow rabbit holes into a smooth, guided process.

Tools Used

Resources