As a DevOps engineer and cloud architect, I wanted my personal website to reflect both my technical expertise and my commitment to modern development practices. In this post, I'll walk through the architecture and implementation details of this website, explaining the technical decisions and tools used.
Technology Stack
Static Site Generator: Pelican
I chose Pelican as the static site generator for several reasons: - Python-based: As someone who works extensively with Python, this allows me to easily extend and customize the site - Markdown Support: Content can be written in Markdown, making it easy to maintain and version control - Flexible Theming: Complete control over the site's appearance through Jinja2 templates - Active Community: Well-maintained with a robust ecosystem of plugins
Design System
The site's design emphasizes professionalism and readability through:
Color Palette
- Burgundy (#6B1D1D): Primary accent color for headings and important elements
- Red (#B92D2D): Secondary accent for interactive elements
- Cream (#FFF6E9): Background color for improved readability
- Navy (#1B2B44): Header and footer backgrounds
- Light Blue (#9FB4D1): Subtle accents and hover states
Typography
- Font Family: Inter with system fallbacks
- Font Features: Ligatures and kerning for better readability
- Font Weights: 400 for body text, 600 for emphasis, 800 for headings
- Line Heights: 1.6 for body text, 1.2 for headings
Interactive Elements
- Subtle hover animations on cards and buttons
- Smooth transitions for color changes
- Consistent shadow effects for depth
- Responsive design patterns
Infrastructure and Deployment
Cloudflare Pages
The site is hosted on Cloudflare Pages, providing: - Global CDN with automatic HTTPS - Zero-configuration deployment - Automatic builds from Git - Preview deployments for pull requests
Infrastructure as Code with Pulumi
All infrastructure is managed through Pulumi using Python, allowing us to: - Define infrastructure in Python for consistency - Manage Cloudflare configurations programmatically - Version control our infrastructure - Automate DNS and security settings
Here's our Pulumi configuration:
import pulumi
import pulumi_cloudflare as cloudflare
# Create a Cloudflare Pages project
pages_project = cloudflare.PagesProject(
"joelmerrick-blog",
account_id=account_id,
name="joelmerrick-blog",
production_branch="main",
build_config=cloudflare.PagesProjectBuildConfigArgs(
build_command="pelican content -s publishconf.py",
destination_dir="output",
),
deployment_configs=cloudflare.PagesProjectDeploymentConfigsArgs(
production=cloudflare.PagesProjectDeploymentConfigsProductionArgs(
environment_variables={
"PYTHON_VERSION": "3.12",
"SITEURL": "https://joelmerrick.co.uk",
},
),
preview=cloudflare.PagesProjectDeploymentConfigsPreviewArgs(
environment_variables={
"PYTHON_VERSION": "3.12",
"SITEURL": "${CF_PAGES_URL}",
},
),
),
)
CI/CD Pipeline
The continuous integration and deployment pipeline is implemented using GitHub Actions, automating: 1. Code quality checks (black, isort, flake8, mypy) 2. Testing with pytest 3. Building with Pelican 4. Infrastructure deployment with Pulumi 5. Deployment verification
Additionally, we use GitHub's Dependabot for automated dependency management:
graph TD
A[Dependabot] --> B[Daily Checks]
B --> C{Updates Available?}
C -->|Yes| D[Create PR]
D --> E[Run CI Tests]
E --> F{Tests Pass?}
F -->|Yes| G[Ready for Review]
G --> H[Auto-merge if Configured]
F -->|No| I[PR Needs Attention]
C -->|No| J[End]
The dependency management workflow: 1. Monitors three ecosystems: - Python (pip) dependencies - npm packages - GitHub Actions 2. Creates separate pull requests for each update 3. Runs our full test suite 4. Labels and assigns reviewers automatically 5. Can be configured for auto-merge on passing tests
Here's our Dependabot configuration:
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "daily"
labels:
- "dependencies"
- "python"
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
labels:
- "dependencies"
- "javascript"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
labels:
- "dependencies"
- "github-actions"
Here's our main workflow:
name: Build and Deploy
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: write
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Format code
run: |
pip install black isort flake8 mypy
black .
isort .
- name: Commit changes
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add .
git diff --quiet && git diff --staged --quiet || git commit -m "Apply code formatting"
- name: Push changes
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}
Testing and Quality Assurance
The project includes comprehensive testing: - Unit Tests: Testing individual components and utilities - Integration Tests: Ensuring different parts work together - Link Checking: Validating internal and external links - HTML Validation: Ensuring valid HTML output - Accessibility Testing: Using tools like Pa11y for accessibility compliance - Deployment Testing: Automated verification of DNS, SSL, and custom domains
Here's our testing workflow:
graph LR
A[Code Changes] --> B[Unit Tests]
B --> C[Integration Tests]
C --> D[E2E Tests]
D --> E[Security Checks]
E --> F[Deploy]
subgraph Security Checks
G[Dependabot Alerts]
H[Vulnerability Scan]
I[License Check]
end
Performance Optimization
Several optimizations are implemented: 1. Image Optimization: Automatic WebP conversion and responsive images 2. CSS Minification: Reducing CSS file size 3. Lazy Loading: For images and non-critical resources 4. Cache Headers: Proper cache control headers for static assets 5. Critical CSS: Inlining critical styles for faster initial render 6. Modern CSS Features: Using CSS variables and modern layout techniques
Security Considerations
Security is implemented through multiple layers: - HTTPS Only: Forced HTTPS through Cloudflare - Content Security Policy: Strict CSP headers - SRI Hashes: For external resources - Security Headers: Including HSTS, X-Content-Type-Options, etc. - SSL/TLS Configuration: Strict SSL mode with minimum TLS 1.2 - Dependency Management: * Automated updates via Dependabot * Security vulnerability scanning * Automated testing of updates * Version pinning and resolutions * Strict engine requirements * Daily monitoring of three ecosystems (Python, npm, GitHub Actions)
Here's our security architecture:
graph TD
A[User Request] --> B[Cloudflare CDN]
B --> C{Security Checks}
C --> D[WAF Rules]
C --> E[Bot Protection]
C --> F[DDoS Mitigation]
C --> G[SSL/TLS]
C --> H[Security Headers]
subgraph Headers
I[CSP]
J[HSTS]
K[X-Frame-Options]
L[Referrer-Policy]
end
Development Workflow
The development workflow is streamlined for efficiency: 1. Local development using Poetry for dependency management 2. Pre-commit hooks for code quality 3. Automated testing on pull requests 4. Preview deployments for visual verification 5. Automated production deployments with verification
Here's our development workflow:
flowchart LR
A[Local Changes] --> B[Pre-commit Hooks]
B --> C[Push to GitHub]
C --> D[CI/CD Pipeline]
D --> E[Preview Deploy]
E --> F{Approved?}
F -->|Yes| G[Production Deploy]
F -->|No| A
Future Improvements
Planned enhancements include: - Integration with a headless CMS for easier content management - Enhanced search functionality - Performance monitoring and analytics - Integration with external services via APIs - Automated image optimization pipeline - Advanced caching strategies
Conclusion
Building this site has been an exercise in applying modern web development practices while keeping things simple and maintainable. The combination of Pelican, Cloudflare Pages, and automated workflows provides a robust foundation that can evolve with my needs.
The complete source code is available on GitHub, demonstrating these concepts in practice.