Building My Personal Infrastructure with Docker

I run a bunch of services on my VPS. Here's how Docker Compose keeps it all manageable.

The Setup

I have a single DigitalOcean droplet running multiple services:

  • This blog
  • TextGuard demo
  • Email server
  • Postgres databases
  • Nginx reverse proxy
  • Monitoring

Docker Compose makes this manageable.

The Structure

My infra-core repo has a docker-compose for each service, plus a shared network:

# networks.yml
networks:
  proxy:
    external: true
  internal:
    external: true
docker network create proxy
docker network create internal

Nginx as Reverse Proxy

All HTTP traffic goes through Nginx:

# nginx/docker-compose.yml
services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./conf.d:/etc/nginx/conf.d
      - ./ssl:/etc/letsencrypt
    networks:
      - proxy

Each service gets a server block:

# conf.d/textguard.conf
server {
    listen 443 ssl;
    server_name textguard.chrishacia.com;
    
    ssl_certificate /etc/letsencrypt/live/textguard.chrishacia.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/textguard.chrishacia.com/privkey.pem;
    
    location / {
        proxy_pass http://textguard:4000;
        proxy_set_header Host $host;
    }
}

Service Example

Each app lives in its own directory:

# textguard/docker-compose.yml
services:
  textguard:
    build: .
    restart: unless-stopped
    networks:
      - proxy
    environment:
      - NODE_ENV=production

Deploy with:

cd textguard
docker compose up -d --build

Shared Database

Multiple apps can share a Postgres instance:

services:
  postgres:
    image: postgres:15
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - internal
    environment:
      - POSTGRES_PASSWORD=${DB_PASSWORD}

Apps connect via the internal network.

SSL with Certbot

docker run --rm \
  -v /path/to/ssl:/etc/letsencrypt \
  -v /path/to/www:/var/www/certbot \
  certbot/certbot certonly \
  --webroot -w /var/www/certbot \
  -d textguard.chrishacia.com

Auto-renewal via cron.

Benefits

1. **Isolation** - Each service is contained 2. **Reproducibility** - Clone repo, run compose, done 3. **Easy updates** - `docker compose pull && docker compose up -d` 4. **Resource sharing** - One Postgres, one Nginx

Running your own infrastructure is educational. You learn so much about networking, security, and deployment.

Back to Journal