Adding a Blog
Step-by-step guide to add a 4th (or Nth) blog to the platform.
Time estimate: 30-60 minutes Requires: Server SSH access, Ghost MCP restart, n8n access
Prerequisites
- [ ] Domain name (or camlab.dev subdomain) with DNS pointing to server
- [ ] Blog niche/topic decided
- [ ] Brand guidelines written (target audience, tone, image style)
- [ ] Reddit subreddits identified for research
Step 1: Choose a Short Name
Pick a short identifier (lowercase, no spaces/hyphens). Used everywhere as a key.
Example: newblog
This will appear in: container names, database names, directory paths, env vars.
Step 2: MySQL Database
ssh camlab
docker exec -it mysql mysql -u root -p
CREATE DATABASE ghost_newblog;
CREATE USER 'ghost_newblog'@'%' IDENTIFIED BY '<generate-password>';
GRANT ALL ON ghost_newblog.* TO 'ghost_newblog'@'%';
FLUSH PRIVILEGES;
EXIT;
Step 3: Environment Variables
Add to /opt/camlab/.env:
# Ghost DB - NewBlog
GHOST_NEWBLOG_DB_USER=ghost_newblog
GHOST_NEWBLOG_DB_PASSWORD=<the-password-from-step-2>
GHOST_NEWBLOG_DB_NAME=ghost_newblog
# Ghost URL
GHOST_NEWBLOG_URL=https://blog.newblog.camlab.dev
# Ghost API Keys (fill after step 5)
GHOST_NEWBLOG_ADMIN_API_KEY=
GHOST_NEWBLOG_CONTENT_API_KEY=
# Ghost MCP
GHOST_NEWBLOG_ADMIN_URL=http://ghost-newblog:2368
GHOST_NEWBLOG_CONTENT_URL=http://ghost-newblog:2368
GHOST_NEWBLOG_MCP_TOKEN=<openssl rand -hex 16>
Update GHOST_INSTANCES:
Step 4: Docker Compose
Add to docker-compose.yml:
ghost-newblog:
image: ghost:6-alpine
container_name: ghost-newblog
restart: unless-stopped
depends_on:
- mysql
ports:
- "127.0.0.1:2371:2368"
environment:
url: ${GHOST_NEWBLOG_URL}
database__client: mysql
database__connection__host: mysql
database__connection__port: 3306
database__connection__user: ${GHOST_NEWBLOG_DB_USER}
database__connection__password: ${GHOST_NEWBLOG_DB_PASSWORD}
database__connection__database: ${GHOST_NEWBLOG_DB_NAME}
NODE_ENV: production
volumes:
- ./ghost/newblog:/var/lib/ghost/content
networks:
- camlab_network
runner-newblog:
build: ./runners
container_name: runner-newblog
restart: unless-stopped
volumes:
- ./runners/newblog/claude-config:/root/.claude
- ./runners/newblog/workspace:/workspace
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- RUNWARE_API_KEY=${RUNWARE_API_KEY}
networks:
- camlab_network
Step 5: Ghost Setup
- Visit
https://blog.newblog.camlab.dev/ghost - Complete setup wizard
- Create integration: Settings → Integrations → Add Custom → "CamLab Automation"
- Copy Admin API Key and Content API Key into
.env
Step 6: Theme
# Copy and customize a theme
cp -r /opt/camlab/ghost/cam4/themes/camlab-casper-cam4 \
/opt/camlab/ghost/newblog/themes/camlab-casper-newblog
# Edit package.json to change name and settings
# Activate in Ghost Admin → Design → Themes
Step 7: Ghost MCP
Restart to pick up new instance:
Verify:
curl -X POST http://localhost:3002/<newblog-mcp-token> \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Step 8: Claude Code Runner
# Create runner config
mkdir -p /opt/camlab/runners/newblog/{claude-config/{agents,config},workspace}
# Copy agent templates and customize
cp /opt/camlab/runners/cam4/claude-config/agents/*.md \
/opt/camlab/runners/newblog/claude-config/agents/
# Create brand guidelines for new blog
# Edit: /opt/camlab/runners/newblog/claude-config/config/brand-guidelines.json
# Create MCP config with newblog Ghost token
cat > /opt/camlab/runners/newblog/claude-config/.mcp.json << 'EOF'
{
"mcpServers": {
"ghost": { "type": "http", "url": "http://ghost-mcp:3002/<newblog-token>" },
"reddit": { "type": "sse", "url": "http://reddit-mcp:8080/sse" },
"playwright": { "type": "http", "url": "http://playwright-mcp:8931/mcp" },
"runware": { "type": "http", "url": "http://runware-mcp:8081/mcp" }
}
}
EOF
# Start runner
docker compose up -d runner-newblog
# Authenticate Claude
docker exec -it runner-newblog claude
Step 9: Caddy
Add to /etc/caddy/Caddyfile:
Reload: sudo systemctl reload caddy
Step 10: n8n Workflow
- In n8n, duplicate the Cam4 Writer's Room workflow
- Rename to "NewBlog Writer's Room"
- Update all Claude Code nodes:
- Runner container:
runner-newblog - Ghost MCP token in any direct references
- Update schedule trigger (pick a non-overlapping time slot)
- Update Researcher agent with new subreddits
- Test with Manual Trigger
- Activate
Step 11: Update Documentation
- [ ] Add to
docs/containers.md - [ ] Add to
docs/networking.md - [ ] Add to
docs/ghost.md - [ ] Log all actions in
logs/changes.md