What We Built: A Complete Modern Blog Infrastructure
This comprehensive guide documents the creation of a fully-featured, decentralized blog platform with cutting-edge features including Bitcoin Lightning payments, Nostr integration, email-to-blog publishing, and automated GitHub deployments.
Infrastructure Overview
Core Components
- Server: Hetzner Ubuntu VPS (188.34.194.25)
- Static Site Generator: Hugo with PaperMod theme
- Web Server: Nginx with SSL (Let’s Encrypt)
- Domain: emino.app (via Porkbun DNS)
- Version Control: GitHub with automated deployments
- Email Server: Postfix + Dovecot for email-to-blog
- Containers: Docker for services (Alby Hub, Nostr relay)
Features Implemented
1. Lightning Bitcoin Tips β‘
- Address: emin@nuri.com
- Design: Minimalist typography-focused interface
- Colors: Bitcoin orange (#f7931a), black, and white only
- WebLN Support: Full integration with Alby browser extension
- Payment Options:
- One-click WebLN payments for Alby users
- Lightning URI deep links for mobile wallets
- Fallback modal for manual payments
2. Nostr Integration π‘
- Personal Relay: Running at
wss://relay.emino.app - Long-form Content: Posts published as NIP-23 events
- Publishing Script: Automatic cross-posting to Nostr
- Media Handling: Compressed images and videos
- Docker Container: nostr-rs-relay for reliability
3. Email-to-Blog Publishing π§
- Email Address: post@emino.app
- Authorized Senders:
- Features:
- Markdown file attachments supported
- Automatic image compression (max 1920x1080)
- Video compression with FFmpeg (H.264)
- GitHub sync for every email post
- Cron job checks every 15 minutes
4. DNS Configuration π
The following DNS records were configured at Porkbun:
A Record:
Host: @
Answer: 188.34.194.25
TTL: 600
A Record:
Host: www
Answer: 188.34.194.25
TTL: 600
MX Record:
Host: (blank)
Answer: emino.app
Priority: 10
TTL: 600
TXT Record (SPF):
Host: (blank)
Answer: v=spf1 ip4:188.34.194.25 ~all
TTL: 600
TXT Record (DMARC):
Host: _dmarc
Answer: v=DMARC1; p=none; rua=mailto:post@emino.app
TTL: 600
5. GitHub Actions Auto-Deployment π
- Trigger: Any push to main branch
- Actions:
- Pull latest changes
- Clean build directory (removes deleted posts)
- Rebuild with Hugo
- Deploy with rsync (–delete flag)
- Workflow File:
.github/workflows/deploy.yml
6. Security & Authentication π
- SSH Keys: Ed25519 for secure server access
- Email Authentication: Whitelist of authorized senders
- SSL/TLS: Let’s Encrypt certificates
- Firewall: UFW configured for web and email
- Nostr: Optional NSEC environment variable
7. Media & Asset Handling πΌοΈ
- Favicon: Bitcoin-themed with multiple sizes
- Image Compression: Pillow (Python) for optimization
- Video Compression: FFmpeg with H.264 codec
- Static Assets: Served from
/static/media/ - PWA Support: Site manifest with theme colors
Technical Implementation Details
Hugo Configuration (config.toml)
baseURL = "https://emino.app/"
languageCode = "en-us"
title = "emino.app"
theme = "PaperMod"
[params]
env = "production"
defaultTheme = "auto"
ShowShareButtons = true
ShowReadingTime = true
ShowToc = true
ShowBreadCrumbs = true
ShowPostNavLinks = true
ShowCodeCopyButtons = true
Build Script (build.sh)
#!/bin/bash
echo "Cleaning old build..."
rm -rf public/*
echo "Building site with Hugo..."
hugo --minify
echo "Syncing to web root..."
rsync -av --delete public/ /var/www/apps/main/
echo "Build complete!"
Email Processing Flow
- Email sent to post@emino.app with subject “BLOG: Title”
- Cron job runs email_to_blog.py every 15 minutes
- Script checks sender authorization
- Processes markdown or plain text content
- Compresses and embeds media files
- Creates Hugo-formatted markdown post
- Rebuilds site and syncs to GitHub
- Optionally publishes to Nostr
Nostr Publishing Flow
- Parse Hugo markdown post
- Create NIP-23 long-form content event
- Add tags (title, published_at, d-tag for replaceability)
- Sign with private key (NSEC)
- Publish to multiple relays:
- wss://relay.emino.app (own relay)
- wss://relay.damus.io
- wss://nos.lol
- wss://relay.nostr.band
Services Running
Docker Containers
# Alby Hub (Lightning)
docker run -d --name alby-hub \
-p 8080:8080 -p 9735:9735 \
ghcr.io/getalby/hub:latest
# Nostr Relay
docker run -d --name nostr-relay \
-p 8081:8080 \
scsibug/nostr-rs-relay:latest
Nginx Virtual Hosts
- emino.app: Main blog (port 443/80)
- hub.emino.app: Alby Hub interface (proxy to 8080)
- relay.emino.app: Nostr relay WebSocket (proxy to 8081)
Cron Jobs
# Email checking every 15 minutes
*/15 * * * * cd /var/www/emino-blog && \
./nostr-env/bin/python scripts/email_to_blog.py \
>> /var/log/email-to-blog.log 2>&1
File Structure
/var/www/emino-blog/
βββ config.toml
βββ build.sh
βββ content/posts/
βββ themes/PaperMod/
βββ static/
β βββ media/
β βββ favicon.ico
β βββ site.webmanifest
βββ scripts/
β βββ email_to_blog.py
β βββ nostr_publisher.py
β βββ email_auth.txt
βββ nostr-env/ (Python venv)
βββ .github/workflows/deploy.yml
/var/www/apps/main/ (deployed site)
/var/www/nostr-relay/ (relay config)
/var/www/alby-hub/ (Lightning hub)
Environment Variables Required
# For email-to-blog
BLOG_EMAIL="post@emino.app"
BLOG_EMAIL_PASSWORD="Kilimanjaro##8"
# For Nostr publishing (optional)
NOSTR_NSEC="your-nostr-private-key"
Monitoring & Maintenance
Health Checks
- Blog availability:
curl -I https://emino.app - Lightning tips: Check address at hub.emino.app
- Nostr relay:
wss://relay.emino.appconnection test - Email: Check
/var/log/email-to-blog.log
Common Tasks
# Manual rebuild
cd /var/www/emino-blog && ./build.sh
# Check email processing
./nostr-env/bin/python scripts/email_to_blog.py
# View Docker containers
docker ps
# Check Nginx status
systemctl status nginx
Security Considerations
- Email Whitelist: Only authorized senders can post
- No Public Email Relay: Server only accepts mail for configured domains
- SSL Everything: All services use HTTPS/WSS
- Key Management: NSEC keys stored as environment variables
- Regular Updates: Automated security updates enabled
Performance Optimizations
- Static Site: No database, instant loading
- Image Compression: All images optimized before serving
- Video Compression: H.264 with web-optimized settings
- CDN Ready: Static files can be easily CDN-cached
- Minified Output: Hugo minification enabled
Future Enhancements Possible
- Automated image generation with AI
- Nostr comments system
- Lightning paywall for premium content
- IPFS backup and distribution
- Analytics without tracking
- Automated social media cross-posting
Conclusion
This infrastructure represents a modern, decentralized approach to blogging that combines:
- Traditional web (Hugo static site)
- Web3 payments (Lightning Bitcoin)
- Decentralized social (Nostr protocol)
- Email convenience (post-by-email)
- Developer workflow (GitHub CI/CD)
The entire stack is self-hosted, privacy-respecting, and built with open-source technologies. It demonstrates how individual creators can own their complete publishing infrastructure while maintaining modern conveniences and integrations.
Resources & Links
- Live Site: emino.app
- Lightning Address: emin@nuri.com
- Nostr Relay: wss://relay.emino.app
- GitHub: github.com/eminogrande/emino-blog
This post was created to document the complete infrastructure build process. If you can read this, all systems are working correctly! β‘π