Initial commit: web-hosts infrastructure

- hostctl.sh management script for starting/stopping/restarting hosts
- test.coppertone.tech domain setup with compose.yaml
- deploy.sh for automated deployments from testing branch
- frontend-nginx.conf for static file serving

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Administrator
2025-11-23 19:54:01 +01:00
parent 57669db6ac
commit 69a28b0537
9 changed files with 1006 additions and 55 deletions

View File

@@ -0,0 +1,41 @@
# test.coppertone.tech
## Directory Structure
```
test.coppertone.tech/
├── compose.yaml # Podman compose configuration
├── www/ # Static website files
├── data/ # Persistent data volumes
├── config/ # Configuration files
└── README.md # This file
```
## Port Assignment
- Main site (test.coppertone.tech): `127.0.0.1:9100`
- API (api.test.coppertone.tech): `127.0.0.1:9101` (if enabled)
## Commands
```bash
# Start the domain
hostctl start test.coppertone.tech
# Stop the domain
hostctl stop test.coppertone.tech
# View logs
hostctl logs test.coppertone.tech
# Check status
hostctl status test.coppertone.tech
```
## Nginx Configuration
After starting the containers, add nginx configuration:
```bash
sudo /docker/www/startup.sh add-domain test.coppertone.tech 9100
```

View File

@@ -0,0 +1,99 @@
# Compose file for test.coppertone.tech
# Builds from CopperTone.Tech repo (develop branch)
# All services bind to 127.0.0.1 only (routed via nginx reverse proxy)
#
# Deploy with: ./deploy.sh
# Or manually: podman-compose down && podman-compose build && podman-compose up -d
services:
# Frontend from develop branch
frontend:
build:
context: ./repo/frontend
dockerfile: Containerfile
container_name: test-coppertone-tech-frontend
restart: unless-stopped
ports:
- "127.0.0.1:9100:80"
volumes:
- ./frontend-nginx.conf:/etc/nginx/conf.d/default.conf:ro
environment:
- VITE_API_BASE_URL=https://test.coppertone.tech/api
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 3
# Auth service
auth-service:
build:
context: ./repo/backend/functions/auth-service
dockerfile: Containerfile
container_name: test-coppertone-tech-auth
restart: unless-stopped
ports:
- "127.0.0.1:9102:8080"
environment:
JWT_SECRET: ${JWT_SECRET:-test_jwt_secret_key_change_me_in_production_at_least_64_characters_long}
DEFAULT_USER_ROLE: ${DEFAULT_USER_ROLE:-CLIENT}
DB_HOST: db
DB_USER: ${DB_USER:-testuser}
DB_PASSWORD: ${DB_PASSWORD:-testpassword}
DB_NAME: ${DB_NAME:-testcoppertone_db}
DB_SSL_MODE: ${DB_SSL_MODE:-disable}
CORS_ALLOW_ORIGIN: https://test.coppertone.tech
depends_on:
- db
# Work management service
work-management-service:
build:
context: ./repo/backend/functions/work-management-service
dockerfile: Containerfile
container_name: test-coppertone-tech-work-mgmt
restart: unless-stopped
ports:
- "127.0.0.1:9103:8080"
environment:
JWT_SECRET: ${JWT_SECRET:-test_jwt_secret_key_change_me_in_production_at_least_64_characters_long}
DB_HOST: db
DB_USER: ${DB_USER:-testuser}
DB_PASSWORD: ${DB_PASSWORD:-testpassword}
DB_NAME: ${DB_NAME:-testcoppertone_db}
DB_SSL_MODE: ${DB_SSL_MODE:-disable}
CORS_ALLOW_ORIGIN: https://test.coppertone.tech
depends_on:
- db
# Blog service
blog-service:
build:
context: ./repo/backend/functions/blog-service
dockerfile: Containerfile
container_name: test-coppertone-tech-blog
restart: unless-stopped
ports:
- "127.0.0.1:9105:8080"
environment:
JWT_SECRET: ${JWT_SECRET:-test_jwt_secret_key_change_me_in_production_at_least_64_characters_long}
DB_HOST: db
DB_USER: ${DB_USER:-testuser}
DB_PASSWORD: ${DB_PASSWORD:-testpassword}
DB_NAME: ${DB_NAME:-testcoppertone_db}
DB_SSL_MODE: ${DB_SSL_MODE:-disable}
CORS_ALLOW_ORIGIN: https://test.coppertone.tech
depends_on:
- db
# Database for test environment
db:
image: postgres:16-alpine
container_name: test-coppertone-tech-db
restart: unless-stopped
environment:
POSTGRES_DB: testcoppertone_db
POSTGRES_USER: testuser
POSTGRES_PASSWORD: testpassword
volumes:
- ./data/postgres:/var/lib/postgresql/data

View File

@@ -0,0 +1,139 @@
#!/bin/bash
#
# Deploy script for test.coppertone.tech
# Pulls latest from develop branch, rebuilds, and restarts containers
#
# Usage:
# ./deploy.sh # Full deploy (pull, build, restart)
# ./deploy.sh pull # Just pull latest code
# ./deploy.sh build # Just rebuild containers
# ./deploy.sh restart # Just restart containers
# ./deploy.sh status # Show status
# ./deploy.sh logs # Show logs
#
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_DIR="$SCRIPT_DIR/repo"
BRANCH="${DEPLOY_BRANCH:-testing}"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[OK]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
cd "$SCRIPT_DIR"
pull_latest() {
log_info "Pulling latest from $BRANCH branch..."
cd "$REPO_DIR"
# Ensure we're on the right branch
current_branch=$(git branch --show-current)
if [ "$current_branch" != "$BRANCH" ]; then
log_info "Switching from $current_branch to $BRANCH..."
git checkout "$BRANCH"
fi
# Pull latest
git fetch origin "$BRANCH"
git reset --hard "origin/$BRANCH"
# Show latest commit
log_success "Updated to: $(git log -1 --oneline)"
cd "$SCRIPT_DIR"
}
build_containers() {
log_info "Building containers..."
podman-compose build --no-cache
log_success "Build complete"
}
stop_containers() {
log_info "Stopping containers..."
podman-compose down 2>/dev/null || true
log_success "Containers stopped"
}
start_containers() {
log_info "Starting containers..."
podman-compose up -d
log_success "Containers started"
}
show_status() {
log_info "Container status:"
podman-compose ps
echo ""
log_info "Recent commits:"
cd "$REPO_DIR"
git log -3 --oneline
cd "$SCRIPT_DIR"
}
show_logs() {
podman-compose logs -f --tail 50
}
full_deploy() {
echo "=========================================="
echo " Deploying test.coppertone.tech"
echo " Branch: $BRANCH"
echo "=========================================="
echo ""
pull_latest
echo ""
stop_containers
echo ""
build_containers
echo ""
start_containers
echo ""
log_success "=========================================="
log_success " Deployment complete!"
log_success "=========================================="
echo ""
show_status
}
case "${1:-deploy}" in
deploy|"")
full_deploy
;;
pull)
pull_latest
;;
build)
build_containers
;;
restart)
stop_containers
start_containers
;;
stop)
stop_containers
;;
start)
start_containers
;;
status)
show_status
;;
logs)
show_logs
;;
*)
echo "Usage: $0 {deploy|pull|build|restart|stop|start|status|logs}"
exit 1
;;
esac

View File

@@ -0,0 +1,44 @@
# Simplified nginx config for test.coppertone.tech frontend
# API routing is handled by the external nginx reverse proxy
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
# Security Headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Prevent caching of index.html
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
# Cache static assets
location /assets/ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
# Serve markdown files
location ~* \.md$ {
types { text/plain md; }
add_header Content-Type text/plain;
}
# SPA routing - serve index.html for all non-file requests
location / {
try_files $uri $uri/ /index.html;
}
# Health check
location /health {
return 200 "OK";
add_header Content-Type text/plain;
}
}

View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome to test.coppertone.tech</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.container {
text-align: center;
padding: 2rem;
}
h1 { font-size: 3rem; margin-bottom: 0.5rem; }
p { font-size: 1.2rem; opacity: 0.9; }
</style>
</head>
<body>
<div class="container">
<h1>test.coppertone.tech</h1>
<p>Your site is ready to be configured.</p>
</div>
</body>
</html>