# Deployment Guide Complete setup for deploying the portfolio site with Docker, Caddy, and Oracle Cloud VPS. ## Architecture ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Cloudflare │────▶│ Oracle VPS │────▶│ Vite Dev │ │ (DNS + Proxy) │ │ (Caddy) │ │ Server │ │ │ │ Port 80/443 │────▶│ Port 5173 │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ ▼ ┌─────────────────┐ │ Docker │ │ (Caddy) │ └─────────────────┘ ``` ## Prerequisites - Oracle Cloud VPS (or similar) - Domain name (Cloudflare recommended) - Docker + Docker Compose installed - Git access to repository ## Server Setup ### 1. Provision VPS **Oracle Cloud Free Tier:** 1. Create instance (Ubuntu 22.04/24.04 ARM or AMD) 2. Add ingress rules for ports 22, 80, 443 3. Note the public IP **Open Ports in Oracle Console:** 1. Networking → Virtual Cloud Networks 2. Click your VCN → Subnets 3. Security Lists → Default Security List 4. Add Ingress Rules: - TCP 80 from 0.0.0.0/0 - TCP 443 from 0.0.0.0/0 - TCP 22 from your IP (SSH) ### 2. Install Dependencies ```bash # Update system sudo apt update && sudo apt upgrade -y # Install Docker curl -fsSL https://get.docker.com | sh sudo usermod -aG docker $USER newgrp docker # Install Node.js 22 curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt install -y nodejs # Verify node -v # Should be 20.19+ or 22.12+ npm -v docker --version ``` ### 3. Clone Repository ```bash sudo mkdir -p /opt/peters-portfolio-site sudo chown $USER:$USER /opt/peters-portfolio-site cd /opt/peters-portfolio-site git clone https://git.dustin.coffee/hobokenchicken/peters-portfolio-site.git . ``` ### 4. Configure Caddy Create directory structure: ```bash mkdir -p docker_configs/caddy/conf mkdir -p docker_configs/caddy/site mkdir -p docker_configs/caddy/caddy_data mkdir -p docker_configs/caddy/caddy_config mkdir -p docker_configs/caddy/logs ``` Create `docker_configs/caddy/conf/Caddyfile`: ```caddy pwlmyers.org { reverse_proxy 172.20.1.232:5173 log { output file /var/log/caddy/access.log format json } # Optional: Add headers header { X-Content-Type-Options nosniff X-Frame-Options DENY X-XSS-Protection "1; mode=block" } } ``` **Note:** Adjust `172.20.1.232` to match your Vite server's IP (check with `ip addr show`) ### 5. Docker Compose for Caddy Create `compose.caddy.yaml`: ```yaml services: caddy: image: caddy:latest restart: unless-stopped ports: - "80:80" - "443:443" - "443:443/udp" volumes: - ./docker_configs/caddy/conf:/etc/caddy - ./docker_configs/caddy/site:/srv - ./docker_configs/caddy/caddy_data:/data - ./docker_configs/caddy/caddy_config:/config - ./docker_configs/caddy/logs:/var/log/caddy networks: - caddy_network networks: caddy_network: driver: bridge ``` ### 6. DNS Configuration (Cloudflare) 1. Log into Cloudflare dashboard 2. Select your domain 3. **DNS** tab → Add records: - Type: `A` - Name: `@` (root) or `www` - Content: `150.136.209.11` (your VPS IP) - Proxy status: 🟠 Orange cloud (proxied) or ⚪ Gray cloud (DNS only) - TTL: Auto 4. **SSL/TLS** tab: - Mode: **Full (strict)** or **Full** - Always Use HTTPS: On ### 7. Deploy Application ```bash cd /opt/peters-portfolio-site # Copy docs to public cp -r docs/* public/docs/ # Install dependencies npm install # Start Vite dev server (background) nohup npm run dev > vite.log 2>&1 & # Start Caddy docker compose -f compose.caddy.yaml up -d ``` ### 8. Verify Deployment ```bash # Check Caddy is running docker ps | grep caddy # Check Vite is running ps aux | grep vite curl http://172.20.1.232:5173/ # Test from VPS curl -H "Host: pwlmyers.org" http://localhost/ # Test HTTPS (after DNS propagates) curl -v https://pwlmyers.org/ ``` ## Updates ### Pull and Update ```bash cd /opt/peters-portfolio-site # Pull latest changes git pull # Reinstall if package.json changed npm install # Copy any new docs cp -r docs/* public/docs/ # Restart Vite pkill -f vite || true nohup npm run dev > vite.log 2>&1 & # Restart Caddy if config changed docker compose -f compose.caddy.yaml restart ``` ### View Logs ```bash # Vite logs tail -f vite.log # Caddy logs docker logs -f ubuntu-caddy-1 tail -f docker_configs/caddy/logs/access.log ``` ## Troubleshooting ### SSL Certificate Issues If Caddy fails to get Let's Encrypt certificate: ```bash # Check Cloudflare proxy status dig pwlmyers.org +short # Should return your VPS IP, not Cloudflare IPs # If using Cloudflare proxy (orange cloud): # - Use Cloudflare Origin Certificate # - Or switch to DNS only (gray cloud) for Let's Encrypt ``` ### Port Already in Use ```bash # Find what's using port 80/443 sudo netstat -tlnp | grep -E ':(80|443)' # Stop conflicting service sudo systemctl stop nginx apache2 ``` ### Vite Not Accessible ```bash # Check Vite is listening on all interfaces netstat -tlnp | grep 5173 # Should show 0.0.0.0:5173, not 127.0.0.1:5173 # Check allowedHosts in vite.config.ts cat vite.config.ts ``` ### Docker Network Issues ```bash # Check Caddy can reach Vite docker exec ubuntu-caddy-1 wget -qO- http://172.20.1.232:5173/ # If using Docker network instead of host IP: docker network ls docker network inspect caddy_caddy_network ``` ## Alternative: Systemd Service Instead of `nohup`, create a systemd service for Vite: ```bash sudo tee /etc/systemd/system/peters-portfolio.service > /dev/null <<'EOF' [Unit] Description=Peter's Portfolio Vite Dev Server After=network.target [Service] Type=simple User=ubuntu WorkingDirectory=/opt/peters-portfolio-site ExecStart=/usr/bin/npm run dev Restart=always RestartSec=10 Environment=NODE_ENV=development [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable peters-portfolio sudo systemctl start peters-portfolio sudo systemctl status peters-portfolio ``` ## Security Notes - Keep `node_modules` updated: `npm audit fix` - Use Cloudflare proxy for DDoS protection - Consider fail2ban for SSH brute force protection - Regular backups of `docs/` directory ## Support For issues with: - **Application code:** Check README.md troubleshooting section - **Server/Docker:** Check logs with commands above - **DNS/SSL:** Verify Cloudflare settings and Oracle firewall rules