You're reading this on a blog that was built, deployed, and launched with the help of an AI — specifically, Claude Code, Anthropic's coding assistant that lives in your terminal. No drag-and-drop website builders. No WordPress. Just a conversation in a terminal and an AWS free tier account.

This is the story of how that happened, step by step. Whether you're a developer curious about AI-assisted workflows or someone who's never touched a terminal, I hope this gives you a feel for what's possible today.


The Starting Point

Here's what I had before we began:

  • A Flask blog app called Polarden sitting on my laptop — already written, never deployed
  • An AWS account with the CLI (command-line interface) installed
  • A domain name (polarden.io) registered through AWS Route 53
  • Claude Code running in my terminal

That's it. No server running anywhere. No database. Just code on a laptop and a dream.

I typed a simple message to Claude: "I want you to control all my AWS setup using AWS CLI."

And we were off.


Step 1: Making Sure AWS Can Hear Us

Before building anything, we needed to verify that my laptop could actually talk to AWS. Think of the AWS CLI as a remote control for Amazon's cloud — but it only works if it's paired to your account.

Claude ran a single command to check:

aws sts get-caller-identity

First attempt? Failed. My credentials had expired. After I regenerated fresh access keys in the AWS console and reconfigured, we tried again:

{
    "UserId": "AIDA2CV22TLJQ5S6AEUDL",
    "Account": "692955290323",
    "Arn": "arn:aws:iam::692955290323:user/claude-code"
}

We had a connection. AWS knew who we were.

A Security Catch

Before moving on, Claude spotted something I'd missed — my .env.example file (a template that gets shared publicly in git repositories) contained real AWS credentials. That's like leaving your house key taped to the front door with a label that says "HOUSE KEY."

Claude flagged it immediately and recommended keeping real secrets in .env (which is hidden from git) and only placeholders in .env.example. A small thing that could have been a big problem.


Step 2: Launching a Server in the Cloud

Next, I asked Claude to create a free-tier EC2 instance. EC2 is Amazon's virtual server service — essentially, a computer in the cloud that runs 24/7 so your website is always available.

Here's what Claude set up:

| Setting | Value | |---------|-------| | Instance type | t2.micro — free for 12 months | | Operating system | Amazon Linux 2023 | | Region | us-west-1 (N. California) | | Storage | 8 GB |

But before launching the server, Claude needed to create two things:

An SSH Key Pair — Your Server's Front Door Key

SSH is how you securely connect to a remote server. Claude generated a key pair and saved it to my machine:

aws ec2 create-key-pair --key-name polarden-key \
  --query 'KeyMaterial' --output text > ~/.ssh/polarden-key.pem
chmod 400 ~/.ssh/polarden-key.pem

That .pem file is the only way to log into the server. Lose it, and you're locked out. Share it, and anyone can get in.

A Security Group — The Server's Firewall

A security group defines who can access the server and how. Claude asked me: "Do you want to restrict SSH to your current IP only?"

Yes. Absolutely.

Claude looked up my public IP, then created rules:

  • Port 22 (SSH): Only my IP address — 108.53.187.224/32. Nobody else on Earth can SSH in.
  • Port 80 (HTTP): Open to everyone — so people can visit the blog.
  • Port 443 (HTTPS): Open to everyone — for secure, encrypted connections.

Launch

With the key and firewall in place, Claude launched the instance:

aws ec2 run-instances --instance-type t2.micro \
  --image-id ami-0e2de80e7636c4837 \
  --key-name polarden-key \
  --security-group-ids sg-0a3b3d35ea0188409 \
  --tag-specifications '[{"ResourceType":"instance","Tags":[{"Key":"Name","Value":"polarden"}]}]'

Thirty seconds later:

Instance ID:  i-071d58f8cc8413661
Public IP:    54.177.226.69
State:        running

We had a server.


Step 3: Setting Up the Database

Every blog needs a place to store posts, comments, and user accounts. Polarden uses SQLite — a lightweight database that lives as a single file on the server. No separate database server needed. No monthly fees.

This step required some problem-solving. The app was built on my Mac (osx-arm64), but the server runs Linux (linux-64). Claude updated the project config to support both platforms, then:

  1. Copied the app to the server using rsync
  2. Installed the Python package manager (pixi) on the server
  3. Installed all dependencies — Flask, SQLAlchemy, Gunicorn, and friends
  4. Initialized the database — creating three tables:

| Table | What it stores | |-------|---------------| | posts | Blog posts — title, content, slug, cover image, timestamps | | comments | Reader comments — author name, body, approval status | | admins | Admin accounts — username and hashed password |

A quick verification:

ssh -i ~/.ssh/polarden-key.pem ec2-user@54.177.226.69 \
  "sqlite3 ~/polarden/instance/polarden.db '.tables'"
admins   comments   posts

Database: ready.


Step 4: Pointing the Domain

Having a server at 54.177.226.69 is fine, but nobody wants to type an IP address into their browser. I already had polarden.io registered with AWS Route 53, so I asked Claude to connect it.

Claude checked my hosted zones, found polarden.io, and created two A records — DNS entries that tell the internet "when someone types this domain, send them to this IP address":

aws route53 change-resource-record-sets --hosted-zone-id Z0433781REMOI64VF527 \
  --change-batch '{
    "Changes": [
      {"Action":"CREATE","ResourceRecordSet":{"Name":"polarden.io","Type":"A","TTL":300,"ResourceRecords":[{"Value":"54.177.226.69"}]}},
      {"Action":"CREATE","ResourceRecordSet":{"Name":"www.polarden.io","Type":"A","TTL":300,"ResourceRecords":[{"Value":"54.177.226.69"}]}}
    ]
  }'

After about 30 seconds, DNS propagated:

dig +short polarden.io
# 54.177.226.69

Both polarden.io and www.polarden.io now pointed to our server.


Step 5: Going Live

This was the big one. Four things needed to happen:

1. Nginx — The Traffic Director

Nginx (pronounced "engine-x") is a web server that sits in front of your app and directs traffic. It handles incoming requests from the internet and forwards them to your application. Claude configured it to:

  • Listen on ports 80 and 443
  • Forward requests to Gunicorn (the Python app server) running on port 8000
  • Serve static files (CSS, images) directly for better performance

2. Gunicorn — The App Runner

Gunicorn is the engine that actually runs the Python blog application. Claude set it up as a systemd service — meaning it starts automatically when the server boots and restarts itself if it crashes:

[Service]
User=ec2-user
WorkingDirectory=/home/ec2-user/polarden
ExecStart=/home/ec2-user/.pixi/bin/pixi run serve
Restart=always

A quick health check confirmed it was alive:

HTTP 200 ✓

3. HTTPS — The Padlock

No modern website should run without HTTPS. It encrypts everything between your browser and the server. Claude installed Certbot (from Let's Encrypt) and obtained a free SSL certificate:

sudo certbot --nginx -d polarden.io -d www.polarden.io \
  --email inki1104@gmail.com --agree-tos --redirect
Successfully deployed certificate for polarden.io
Successfully deployed certificate for www.polarden.io

The --redirect flag means anyone visiting http://polarden.io automatically gets redirected to https://polarden.io. The certificate auto-renews, so we never have to think about it again.

4. Admin Account — The Keys to the Blog

Finally, Claude created an admin account so I could actually log in and write posts:

pixi run python create_admin.py den <password>

The Result

From first message to live blog: one conversation. Here's what we ended up with:

  • A t2.micro EC2 instance running Amazon Linux 2023 — free for 12 months
  • SQLite database with posts, comments, and admin tables
  • Nginx reverse proxy with static file serving
  • Gunicorn application server running as a self-healing systemd service
  • HTTPS via Let's Encrypt with automatic renewal and HTTP-to-HTTPS redirect
  • DNS configured through Route 53 — polarden.io and www.polarden.io
  • SSH access locked down to a single IP address
  • Total monthly cost: $0 (within AWS free tier)

What I Learned

AI doesn't replace understanding — it accelerates it. I still needed to know what I wanted (a blog, on AWS, with a custom domain). But Claude handled the parts that usually send people down hours-long rabbit holes: the right AMI ID for my region, the correct Nginx config syntax for Amazon Linux vs. Ubuntu, the exact Certbot flags for non-interactive mode.

Security comes up naturally in conversation. Claude caught the credentials in my .env.example before I pushed them to a public repo. It asked before opening SSH to the world. These aren't things I would have forgotten — but they're things I might have gotten to later, which in security often means too late.

The AWS CLI is more approachable than the console. Clicking through the AWS web console feels like navigating a maze. But expressed as CLI commands in a conversation, each step is one line with a clear purpose. You can see exactly what's happening.


Want to Build Your Own?

Here's the minimal shopping list:

  1. An AWS accountaws.amazon.com (free tier available)
  2. AWS CLIbrew install awscli on Mac
  3. A domain — register one through Route 53 or any registrar
  4. Claude Codeclaude.ai/claude-code
  5. Your app — or fork Polarden and make it your own

Then open your terminal and start talking.


This is the first post on Polarden, and yes — even this post was drafted with Claude's help. The words are mine. The deployment pipeline was a team effort.