Sometimes Code Blog
A personal blog built with Hugo, designed for longevity and simplicity.
Quick Start
- Install Hugo:
brew install hugo - Clone with submodules:
git clone --recurse-submodules <repo-url> - Start development server:
hugo server --buildDrafts - View at: http://localhost:1313
Writing Content
New Post
hugo new content posts/my-new-post.md
Categories
- Use
categories = ['programming']for technical posts - Use
categories = ['family']for personal/family posts
Publishing
- Set
draft = falsein the frontmatter to publish
Project Structure
├── content/
│ ├── posts/ # Blog posts
│ └── pages/ # Static pages (resume, etc.)
├── themes/
│ └── sometimescode/ # Custom theme
├── hugo.toml # Site configuration
└── .gitea/workflows/ # Gitea Actions for CI/CD
Deployment
Automatic Deployment (Gitea Actions)
The site automatically builds and deploys when you push to the main branch using Gitea Actions.
Required Gitea Secrets
Configure these secrets in your Gitea repository settings (Settings → Secrets):
-
SSH_KEY: Private SSH key for deployment authentication# Generate a new SSH key pair on the host server ssh-keygen -t ed25519 -C "gitea-deploy@sometimescode.com" -f ~/.ssh/gitea_deploy # Copy the PRIVATE key content (this goes in Gitea secrets) cat ~/.ssh/gitea_deploy # Add the PUBLIC key to authorized_keys on the host cat ~/.ssh/gitea_deploy.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys -
HOST: IP address to reach the host from the Docker worker- Same-host deployment: Use
172.17.0.1(Docker bridge gateway IP) - Remote server: Use the actual server IP or hostname
- Same-host deployment: Use
-
USERNAME: SSH username on the deployment server- Example:
www-data,ubuntu, ordeploy
- Example:
Important for same-host deployment: When your Gitea worker runs in Docker on the same machine as your web server, use 172.17.0.1 as the HOST. This is the default Docker bridge network IP that allows containers to reach the host machine.
How It Works
- Push to
mainbranch triggers the workflow - Gitea worker (Docker container) checks out the code
- Hugo extended is installed via the peaceiris/actions-hugo action
- Site is built with
hugo --minify - SSH connection is established to the host (via
172.17.0.1for same-host) - Built files in
public/are copied via SCP to/var/www/sometimescode.com/ - SSH keys are cleaned up after deployment
Server Setup
-
Server Requirements:
- Ubuntu 22.04+ or similar Linux server
- Nginx or Caddy web server
- SSL certificate (automatic with Caddy, or use certbot with Nginx)
-
Prepare deployment directory:
# Create web directory sudo mkdir -p /var/www/sometimescode.com # Set appropriate permissions for your deploy user sudo chown -R deploy-user:deploy-user /var/www/sometimescode.com -
Configure Web Server:
Option A: Caddy (Recommended - automatic HTTPS)
# Install Caddy if not already installed sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list sudo apt update sudo apt install caddy # Edit Caddyfile sudo nano /etc/caddy/CaddyfileAdd this configuration:
sometimescode.com { root * /var/www/sometimescode.com file_server encode gzip }# Reload Caddy sudo systemctl reload caddyOption B: Nginx (manual SSL setup)
# Create nginx config sudo nano /etc/nginx/sites-available/sometimescode.com # Enable site sudo ln -s /etc/nginx/sites-available/sometimescode.com /etc/nginx/sites-enabled/ # Get SSL certificate sudo certbot --nginx -d sometimescode.com -d www.sometimescode.com # Restart nginx sudo systemctl restart nginx
Manual Deployment
If needed, you can still deploy manually:
# Build site
hugo --minify
# Upload to server
scp -r public/* user@server:/var/www/sometimescode.com/
Development
- Theme: Custom "sometimescode" theme
- Hugo Version: 0.139.4+ (extended version)
- Content Format: Markdown with YAML frontmatter
- Dark Mode: Custom CSS and JavaScript implementation with toggle button
- CI/CD: Gitea Actions for automated build and deployment
Philosophy
This blog is built for longevity:
- Markdown files: Human-readable, future-proof content
- Static generation: No database dependencies
- Simple theme: Minimal dependencies, maximum compatibility
- Git history: Complete version control of all content
The goal is for this blog to be readable and maintainable for decades to come.