Initial commit... a site is born (again? finally?)

This commit is contained in:
2026-01-30 19:58:22 +00:00
commit 1519dfa460
62 changed files with 5674 additions and 0 deletions

355
DEPLOYMENT.md Normal file
View File

@@ -0,0 +1,355 @@
# Deployment Guide
Quick reference for setting up Woodpecker CI/CD deployment.
## Prerequisites
- Gitea instance with Woodpecker CI configured
- Private Docker registry (Docker Hub, GitHub Container Registry, Harbor, etc.)
- Linode VPS with Docker installed
- SSH access to VPS
## Step-by-Step Setup
### 1. Prepare VPS
SSH into your Linode VPS and install Docker:
```bash
# Update system
sudo apt update && sudo apt upgrade -y
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Create deploy user (optional, recommended)
sudo useradd -m -s /bin/bash deploy
sudo usermod -aG docker deploy
# Verify Docker works
docker --version
docker ps
```
### 2. Generate SSH Key for Deployment
On your local machine or CI server:
```bash
# Generate SSH key pair
ssh-keygen -t ed25519 -C "woodpecker-deploy" -f ~/.ssh/woodpecker_deploy
# Copy public key to VPS
ssh-copy-id -i ~/.ssh/woodpecker_deploy.pub deploy@your-vps-ip
# Test connection
ssh -i ~/.ssh/woodpecker_deploy deploy@your-vps-ip "echo 'Connection successful'"
# Get private key content (copy this to Woodpecker secret)
cat ~/.ssh/woodpecker_deploy
```
### 3. Configure Docker Registry
**Option A: Docker Hub**
```bash
REGISTRY_URL=docker.io
REGISTRY_REPO=docker.io/yourusername/mifi-ventures-landing
REGISTRY_USERNAME=yourusername
# Password: Use Docker Hub access token (not your account password)
# Generate at: https://hub.docker.com/settings/security
```
**Option B: GitHub Container Registry**
```bash
REGISTRY_URL=ghcr.io
REGISTRY_REPO=ghcr.io/yourusername/mifi-ventures-landing
REGISTRY_USERNAME=yourusername
# Password: GitHub Personal Access Token with write:packages scope
# Generate at: https://github.com/settings/tokens
```
**Option C: Self-hosted Registry**
```bash
REGISTRY_URL=registry.example.com
REGISTRY_REPO=registry.example.com/mifi-ventures-landing
REGISTRY_USERNAME=yourusername
# Password: Your registry password or token
```
### 4. Configure Woodpecker Secrets
Navigate to: `Gitea → Repository → Settings → Secrets`
Add these secrets (click "Add secret" for each):
| Name | Value | Notes |
|------|-------|-------|
| `registry_password` | Your registry password/token | From step 3 |
| `deploy_host` | `123.45.67.89` | Your Linode VPS IP |
| `deploy_username` | `deploy` | SSH user from step 1 |
| `deploy_ssh_key` | `-----BEGIN OPENSSH...` | Private key from step 2 |
| `deploy_port` | `22` | Default SSH port |
**Important**: For `deploy_ssh_key`, paste the entire private key including:
```
-----BEGIN OPENSSH PRIVATE KEY-----
...entire key content...
-----END OPENSSH PRIVATE KEY-----
```
### 5. Configure Woodpecker Variables
Navigate to: `Gitea → Repository → Settings → Variables`
Add these variables:
| Name | Value | Example |
|------|-------|---------|
| `REGISTRY_URL` | Registry base URL | `ghcr.io` |
| `REGISTRY_REPO` | Full image path | `ghcr.io/username/mifi-ventures-landing` |
| `REGISTRY_USERNAME` | Registry username | `yourusername` |
| `CONTAINER_NAME` | Container name | `mifi-ventures-landing` |
| `APP_PORT` | Host port | `8080` |
### 6. Test Deployment
#### Local Test Build
```bash
# Clone repo
git clone https://gitea.example.com/you/mifi-ventures-landing.git
cd mifi-ventures-landing
# Build locally
docker build -t test .
# Run locally
docker run -d -p 8080:80 --name test test
# Test
curl http://localhost:8080
# Cleanup
docker stop test && docker rm test
```
#### Trigger CI/CD
```bash
# Make a small change
echo "# Test deployment" >> README.md
# Commit and push to main
git add README.md
git commit -m "test: trigger deployment"
git push origin main
# Watch pipeline in Woodpecker UI
# Check: Gitea → Repository → Pipelines
```
### 7. Verify Deployment
After pipeline completes:
```bash
# Check container is running
ssh deploy@your-vps-ip "docker ps | grep mifi-ventures-landing"
# Check container logs
ssh deploy@your-vps-ip "docker logs mifi-ventures-landing"
# Test HTTP response
curl http://your-vps-ip:8080
# Check from browser
# Visit: http://your-vps-ip:8080
```
## Port Configuration
The pipeline uses `APP_PORT` to expose the container. Choose based on your setup:
### Option 1: Direct Port 80 (No Reverse Proxy)
```bash
APP_PORT=80
# Container listens on port 80 directly
# Access at: http://your-vps-ip
```
### Option 2: Custom Port (With Traefik/Nginx)
```bash
APP_PORT=8080
# Container listens on 8080
# Traefik/Nginx proxies from 80/443 → 8080
# Access via domain: https://mifi.ventures
```
**Note**: With Traefik, security headers are added at the proxy level.
## Traefik Integration Example
If using Traefik as reverse proxy, add labels to container:
```yaml
# In docker-compose.yml or docker run command
labels:
- "traefik.enable=true"
- "traefik.http.routers.mifi.rule=Host(`mifi.ventures`)"
- "traefik.http.routers.mifi.entrypoints=websecure"
- "traefik.http.routers.mifi.tls.certresolver=letsencrypt"
- "traefik.http.services.mifi.loadbalancer.server.port=80"
```
Update Woodpecker deploy script to include labels:
```bash
docker run -d \
--name $CONTAINER_NAME \
--restart unless-stopped \
--label "traefik.enable=true" \
--label "traefik.http.routers.mifi.rule=Host(\`mifi.ventures\`)" \
--label "traefik.http.routers.mifi.entrypoints=websecure" \
--label "traefik.http.routers.mifi.tls.certresolver=letsencrypt" \
--label "traefik.http.services.mifi.loadbalancer.server.port=80" \
--network traefik-public \
$REGISTRY_REPO:latest
```
## Common Issues
### SSH Permission Denied
```bash
# Check key permissions (must be 600)
chmod 600 ~/.ssh/woodpecker_deploy
# Verify public key is on server
ssh deploy@host "cat ~/.ssh/authorized_keys"
# Test with verbose output
ssh -vvv -i ~/.ssh/woodpecker_deploy deploy@host
```
### Registry Login Failed
```bash
# Test login locally
echo "PASSWORD" | docker login registry.example.com -u username --password-stdin
# For GitHub: Ensure token has write:packages scope
# For Docker Hub: Use access token, not password
```
### Container Won't Start
```bash
# Check logs
ssh deploy@host "docker logs mifi-ventures-landing"
# Check for port conflicts
ssh deploy@host "netstat -tulpn | grep :80"
# Verify image pulled successfully
ssh deploy@host "docker images | grep mifi-ventures"
```
### Health Check Fails
```bash
# Check nginx is running
ssh deploy@host "docker exec mifi-ventures-landing ps aux"
# Test internally
ssh deploy@host "docker exec mifi-ventures-landing wget -O- http://localhost/"
# Check if firewall blocking
ssh deploy@host "ufw status"
```
## Rollback Procedure
If deployment fails:
```bash
# SSH to VPS
ssh deploy@your-vps-ip
# List available images
docker images | grep mifi-ventures
# Find previous working SHA
# (from Gitea commit history or Docker labels)
# Stop current container
docker stop mifi-ventures-landing
docker rm mifi-ventures-landing
# Start previous version
docker run -d \
--name mifi-ventures-landing \
--restart unless-stopped \
-p 8080:80 \
registry.example.com/mifi-ventures-landing:PREVIOUS_SHA
# Verify
docker ps | grep mifi-ventures-landing
curl http://localhost:8080
```
## Monitoring
### Container Status
```bash
# Check if running
docker ps | grep mifi-ventures-landing
# View logs (last 100 lines)
docker logs --tail 100 mifi-ventures-landing
# Follow logs in real-time
docker logs -f mifi-ventures-landing
# Check resource usage
docker stats mifi-ventures-landing
```
### Nginx Access Logs
```bash
# View access logs
docker exec mifi-ventures-landing tail -f /var/log/nginx/access.log
# View error logs
docker exec mifi-ventures-landing tail -f /var/log/nginx/error.log
```
### Disk Space
```bash
# Check Docker disk usage
docker system df
# Cleanup old images (automatic in pipeline, or manual)
docker image prune -af --filter "until=72h"
# Full cleanup (careful!)
docker system prune -a --volumes
```
## Security Checklist
- [ ] SSH key is Ed25519 (not RSA)
- [ ] Private key is stored securely in Woodpecker (never in repo)
- [ ] Deploy user has minimal permissions (not root if possible)
- [ ] Registry uses authentication (not public)
- [ ] VPS firewall configured (ufw or iptables)
- [ ] Traefik handles TLS termination (if used)
- [ ] Container runs as non-root user (nginx user)
- [ ] Regular security updates (`apt update && apt upgrade`)
## Next Steps
1. Set up monitoring (Prometheus + Grafana)
2. Configure automated backups
3. Add Slack/Discord notifications to pipeline
4. Set up staging environment
5. Implement blue-green deployments for zero downtime
---
**Last Updated**: 2026-01-29
**Maintainer**: Mike Fitzpatrick