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:
83
.gitignore
vendored
83
.gitignore
vendored
@@ -79,6 +79,8 @@ web_modules/
|
|||||||
.env.test.local
|
.env.test.local
|
||||||
.env.production.local
|
.env.production.local
|
||||||
.env.local
|
.env.local
|
||||||
|
*.env.local
|
||||||
|
*.env.production
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
.cache
|
.cache
|
||||||
@@ -94,16 +96,12 @@ dist
|
|||||||
|
|
||||||
# Gatsby files
|
# Gatsby files
|
||||||
.cache/
|
.cache/
|
||||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
|
||||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
||||||
# public
|
|
||||||
|
|
||||||
# vuepress build output
|
# vuepress build output
|
||||||
.vuepress/dist
|
.vuepress/dist
|
||||||
|
|
||||||
# vuepress v2.x temp and cache directory
|
# vuepress v2.x temp and cache directory
|
||||||
.temp
|
.temp
|
||||||
.cache
|
|
||||||
|
|
||||||
# vitepress build output
|
# vitepress build output
|
||||||
**/.vitepress/dist
|
**/.vitepress/dist
|
||||||
@@ -137,9 +135,6 @@ dist
|
|||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
# ---> Go
|
# ---> Go
|
||||||
# If you prefer the allow list template instead of the deny list, see community template:
|
|
||||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
|
||||||
#
|
|
||||||
# Binaries for programs and plugins
|
# Binaries for programs and plugins
|
||||||
*.exe
|
*.exe
|
||||||
*.exe~
|
*.exe~
|
||||||
@@ -153,19 +148,12 @@ dist
|
|||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
*.out
|
*.out
|
||||||
|
|
||||||
# Dependency directories (remove the comment below to include it)
|
|
||||||
# vendor/
|
|
||||||
|
|
||||||
# Go workspace file
|
# Go workspace file
|
||||||
go.work
|
go.work
|
||||||
go.work.sum
|
go.work.sum
|
||||||
|
|
||||||
# env file
|
|
||||||
.env
|
|
||||||
|
|
||||||
# ---> Rust
|
# ---> Rust
|
||||||
# Generated by Cargo
|
# Generated by Cargo
|
||||||
# will have compiled files and executables
|
|
||||||
debug/
|
debug/
|
||||||
target/
|
target/
|
||||||
|
|
||||||
@@ -175,12 +163,6 @@ target/
|
|||||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
*.pdb
|
*.pdb
|
||||||
|
|
||||||
# RustRover
|
|
||||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
||||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
||||||
#.idea/
|
|
||||||
# ---> C++
|
# ---> C++
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
*.d
|
*.d
|
||||||
@@ -195,11 +177,6 @@ target/
|
|||||||
*.gch
|
*.gch
|
||||||
*.pch
|
*.pch
|
||||||
|
|
||||||
# Compiled Dynamic libraries
|
|
||||||
*.so
|
|
||||||
*.dylib
|
|
||||||
*.dll
|
|
||||||
|
|
||||||
# Fortran module files
|
# Fortran module files
|
||||||
*.mod
|
*.mod
|
||||||
*.smod
|
*.smod
|
||||||
@@ -211,18 +188,11 @@ target/
|
|||||||
*.lib
|
*.lib
|
||||||
|
|
||||||
# Executables
|
# Executables
|
||||||
*.exe
|
|
||||||
*.out
|
|
||||||
*.app
|
*.app
|
||||||
|
|
||||||
# ---> C
|
# ---> C
|
||||||
# Prerequisites
|
|
||||||
*.d
|
|
||||||
|
|
||||||
# Object files
|
# Object files
|
||||||
*.o
|
|
||||||
*.ko
|
*.ko
|
||||||
*.obj
|
|
||||||
*.elf
|
*.elf
|
||||||
|
|
||||||
# Linker output
|
# Linker output
|
||||||
@@ -230,38 +200,15 @@ target/
|
|||||||
*.map
|
*.map
|
||||||
*.exp
|
*.exp
|
||||||
|
|
||||||
# Precompiled Headers
|
|
||||||
*.gch
|
|
||||||
*.pch
|
|
||||||
|
|
||||||
# Libraries
|
|
||||||
*.lib
|
|
||||||
*.a
|
|
||||||
*.la
|
|
||||||
*.lo
|
|
||||||
|
|
||||||
# Shared objects (inc. Windows DLLs)
|
# Shared objects (inc. Windows DLLs)
|
||||||
*.dll
|
|
||||||
*.so
|
|
||||||
*.so.*
|
*.so.*
|
||||||
*.dylib
|
|
||||||
|
|
||||||
# Executables
|
|
||||||
*.exe
|
|
||||||
*.out
|
|
||||||
*.app
|
|
||||||
*.i*86
|
|
||||||
*.x86_64
|
|
||||||
*.hex
|
|
||||||
|
|
||||||
# Debug files
|
# Debug files
|
||||||
*.dSYM/
|
*.dSYM/
|
||||||
*.su
|
*.su
|
||||||
*.idb
|
*.idb
|
||||||
*.pdb
|
|
||||||
|
|
||||||
# Kernel Module Compile Results
|
# Kernel Module Compile Results
|
||||||
*.mod*
|
|
||||||
*.cmd
|
*.cmd
|
||||||
.tmp_versions/
|
.tmp_versions/
|
||||||
modules.order
|
modules.order
|
||||||
@@ -283,3 +230,29 @@ CTestTestfile.cmake
|
|||||||
_deps
|
_deps
|
||||||
CMakeUserPresets.json
|
CMakeUserPresets.json
|
||||||
|
|
||||||
|
# ---> Web Hosts Specific
|
||||||
|
# Data directories
|
||||||
|
**/data/
|
||||||
|
**/postgres-data/
|
||||||
|
|
||||||
|
# Repo clones (managed separately)
|
||||||
|
**/repo/
|
||||||
|
|
||||||
|
# Runtime files
|
||||||
|
*.sock
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Editor files
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
tmp/
|
||||||
|
temp/
|
||||||
|
*.tmp
|
||||||
|
|||||||
41
domains/test.coppertone.tech/README.md
Normal file
41
domains/test.coppertone.tech/README.md
Normal 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
|
||||||
|
```
|
||||||
99
domains/test.coppertone.tech/compose.yaml
Normal file
99
domains/test.coppertone.tech/compose.yaml
Normal 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
|
||||||
139
domains/test.coppertone.tech/deploy.sh
Executable file
139
domains/test.coppertone.tech/deploy.sh
Executable 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
|
||||||
44
domains/test.coppertone.tech/frontend-nginx.conf
Normal file
44
domains/test.coppertone.tech/frontend-nginx.conf
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
domains/test.coppertone.tech/www/index.html
Normal file
32
domains/test.coppertone.tech/www/index.html
Normal 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>
|
||||||
124
scripts/README.md
Normal file
124
scripts/README.md
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
# Web Hosts Management
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This system manages web hosting for multiple domains using:
|
||||||
|
- **Podman Compose** - Container orchestration (rootless)
|
||||||
|
- **Nginx** - Reverse proxy with SSL (rootful, via sudo)
|
||||||
|
- All services bind to `127.0.0.1` only
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
/docker/web-hosts/
|
||||||
|
├── scripts/
|
||||||
|
│ └── hostctl.sh # Main management script
|
||||||
|
├── domains/
|
||||||
|
│ └── <domain>/ # One directory per root domain
|
||||||
|
│ ├── compose.yaml
|
||||||
|
│ ├── www/ # Static files
|
||||||
|
│ ├── data/ # Persistent data
|
||||||
|
│ └── config/ # Configuration
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Create a new domain
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/docker/web-hosts/scripts/hostctl.sh create example.com 9000
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates:
|
||||||
|
- Directory structure at `/docker/web-hosts/domains/example.com/`
|
||||||
|
- Template `compose.yaml` with services bound to `127.0.0.1:9000`
|
||||||
|
- Default `index.html`
|
||||||
|
|
||||||
|
### 2. Customize the compose file
|
||||||
|
|
||||||
|
Edit `/docker/web-hosts/domains/example.com/compose.yaml` to add your services.
|
||||||
|
|
||||||
|
### 3. Start the domain
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/docker/web-hosts/scripts/hostctl.sh start example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Add nginx reverse proxy with SSL
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo /docker/www/startup.sh add-domain example.com 9000
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commands Reference
|
||||||
|
|
||||||
|
| Command | Description |
|
||||||
|
|---------|-------------|
|
||||||
|
| `hostctl list` | List all configured domains |
|
||||||
|
| `hostctl status [domain]` | Show status |
|
||||||
|
| `hostctl start <domain>` | Start a domain |
|
||||||
|
| `hostctl stop <domain>` | Stop a domain |
|
||||||
|
| `hostctl restart <domain>` | Restart a domain |
|
||||||
|
| `hostctl logs <domain>` | View logs |
|
||||||
|
| `hostctl create <domain> [port]` | Create new domain |
|
||||||
|
| `hostctl remove <domain>` | Remove a domain |
|
||||||
|
| `hostctl start-all` | Start all domains |
|
||||||
|
| `hostctl stop-all` | Stop all domains |
|
||||||
|
|
||||||
|
## Port Assignment Convention
|
||||||
|
|
||||||
|
Each root domain gets a port range starting from the specified port:
|
||||||
|
- `<port>`: Main website (www)
|
||||||
|
- `<port+1>`: API subdomain
|
||||||
|
- `<port+2>`: Additional services
|
||||||
|
- etc.
|
||||||
|
|
||||||
|
Example for `example.com` starting at port 9000:
|
||||||
|
- `example.com` → `127.0.0.1:9000`
|
||||||
|
- `api.example.com` → `127.0.0.1:9001`
|
||||||
|
- `admin.example.com` → `127.0.0.1:9002`
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
Internet
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ Nginx (rootful, ports 80/443) │
|
||||||
|
│ /docker/www/ │
|
||||||
|
│ - SSL termination │
|
||||||
|
│ - Reverse proxy │
|
||||||
|
└─────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼ 127.0.0.1:<port>
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ Podman Containers (rootless) │
|
||||||
|
│ /docker/web-hosts/domains/ │
|
||||||
|
│ - Web apps │
|
||||||
|
│ - APIs │
|
||||||
|
│ - Databases │
|
||||||
|
└─────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding Subdomains
|
||||||
|
|
||||||
|
1. Add service to domain's `compose.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
api:
|
||||||
|
image: your-api-image
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:9001:8080"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Restart the domain:
|
||||||
|
```bash
|
||||||
|
hostctl restart example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Add nginx config for subdomain:
|
||||||
|
```bash
|
||||||
|
sudo /docker/www/startup.sh add-domain api.example.com 9001
|
||||||
|
```
|
||||||
1
scripts/hostctl
Symbolic link
1
scripts/hostctl
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
/docker/web-hosts/scripts/hostctl.sh
|
||||||
498
scripts/hostctl.sh
Executable file
498
scripts/hostctl.sh
Executable file
@@ -0,0 +1,498 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Web Host Management Script
|
||||||
|
# Manages podman-compose based web hosts on 127.0.0.1
|
||||||
|
# Each root domain has its own compose file in /docker/web-hosts/domains/<domain>/
|
||||||
|
#
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
CYAN='\033[0;36m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
HOSTS_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
|
DOMAINS_DIR="$HOSTS_DIR/domains"
|
||||||
|
NGINX_STARTUP="/docker/www/startup.sh"
|
||||||
|
|
||||||
|
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"; }
|
||||||
|
log_header() { echo -e "${CYAN}=== $1 ===${NC}"; }
|
||||||
|
|
||||||
|
# Get domain directory
|
||||||
|
get_domain_dir() {
|
||||||
|
local domain=$1
|
||||||
|
echo "$DOMAINS_DIR/$domain"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if domain exists
|
||||||
|
domain_exists() {
|
||||||
|
local domain=$1
|
||||||
|
local domain_dir=$(get_domain_dir "$domain")
|
||||||
|
[ -d "$domain_dir" ] && [ -f "$domain_dir/compose.yaml" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# List all domains
|
||||||
|
list_domains() {
|
||||||
|
log_header "Configured Domains"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ ! -d "$DOMAINS_DIR" ] || [ -z "$(ls -A "$DOMAINS_DIR" 2>/dev/null)" ]; then
|
||||||
|
log_warn "No domains configured yet."
|
||||||
|
echo ""
|
||||||
|
echo "To create a new domain, run:"
|
||||||
|
echo " $0 create <domain>"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
for domain_dir in "$DOMAINS_DIR"/*/; do
|
||||||
|
if [ -d "$domain_dir" ]; then
|
||||||
|
domain=$(basename "$domain_dir")
|
||||||
|
compose_file="$domain_dir/compose.yaml"
|
||||||
|
|
||||||
|
if [ -f "$compose_file" ]; then
|
||||||
|
# Check running status
|
||||||
|
cd "$domain_dir"
|
||||||
|
running_count=$(podman-compose ps -q 2>/dev/null | wc -l)
|
||||||
|
|
||||||
|
if [ "$running_count" -gt 0 ]; then
|
||||||
|
status="${GREEN}RUNNING${NC} ($running_count containers)"
|
||||||
|
else
|
||||||
|
status="${YELLOW}STOPPED${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e " $domain: $status"
|
||||||
|
|
||||||
|
# Show services
|
||||||
|
if [ -f "$compose_file" ]; then
|
||||||
|
services=$(grep -E "^\s+[a-zA-Z0-9_-]+:\s*$" "$compose_file" | sed 's/://g' | xargs)
|
||||||
|
if [ -n "$services" ]; then
|
||||||
|
echo " Services: $services"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Start a domain
|
||||||
|
start_domain() {
|
||||||
|
local domain=$1
|
||||||
|
|
||||||
|
if [ -z "$domain" ]; then
|
||||||
|
log_error "Usage: $0 start <domain>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! domain_exists "$domain"; then
|
||||||
|
log_error "Domain '$domain' not found. Create it first with: $0 create $domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local domain_dir=$(get_domain_dir "$domain")
|
||||||
|
|
||||||
|
log_info "Starting $domain..."
|
||||||
|
cd "$domain_dir"
|
||||||
|
podman-compose up -d
|
||||||
|
|
||||||
|
log_success "$domain started"
|
||||||
|
|
||||||
|
# Show running containers
|
||||||
|
podman-compose ps
|
||||||
|
}
|
||||||
|
|
||||||
|
# Stop a domain
|
||||||
|
stop_domain() {
|
||||||
|
local domain=$1
|
||||||
|
|
||||||
|
if [ -z "$domain" ]; then
|
||||||
|
log_error "Usage: $0 stop <domain>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! domain_exists "$domain"; then
|
||||||
|
log_error "Domain '$domain' not found."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local domain_dir=$(get_domain_dir "$domain")
|
||||||
|
|
||||||
|
log_info "Stopping $domain..."
|
||||||
|
cd "$domain_dir"
|
||||||
|
podman-compose down
|
||||||
|
|
||||||
|
log_success "$domain stopped"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Restart a domain
|
||||||
|
restart_domain() {
|
||||||
|
local domain=$1
|
||||||
|
|
||||||
|
if [ -z "$domain" ]; then
|
||||||
|
log_error "Usage: $0 restart <domain>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
stop_domain "$domain"
|
||||||
|
sleep 1
|
||||||
|
start_domain "$domain"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show domain status
|
||||||
|
status_domain() {
|
||||||
|
local domain=$1
|
||||||
|
|
||||||
|
if [ -z "$domain" ]; then
|
||||||
|
# Show all domains
|
||||||
|
list_domains
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! domain_exists "$domain"; then
|
||||||
|
log_error "Domain '$domain' not found."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local domain_dir=$(get_domain_dir "$domain")
|
||||||
|
|
||||||
|
log_header "Status: $domain"
|
||||||
|
cd "$domain_dir"
|
||||||
|
podman-compose ps
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show domain logs
|
||||||
|
logs_domain() {
|
||||||
|
local domain=$1
|
||||||
|
local service=$2
|
||||||
|
|
||||||
|
if [ -z "$domain" ]; then
|
||||||
|
log_error "Usage: $0 logs <domain> [service]"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! domain_exists "$domain"; then
|
||||||
|
log_error "Domain '$domain' not found."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local domain_dir=$(get_domain_dir "$domain")
|
||||||
|
cd "$domain_dir"
|
||||||
|
|
||||||
|
if [ -n "$service" ]; then
|
||||||
|
podman-compose logs -f "$service"
|
||||||
|
else
|
||||||
|
podman-compose logs -f
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create a new domain
|
||||||
|
create_domain() {
|
||||||
|
local domain=$1
|
||||||
|
local port=$2
|
||||||
|
|
||||||
|
if [ -z "$domain" ]; then
|
||||||
|
log_error "Usage: $0 create <domain> [starting_port]"
|
||||||
|
log_error "Example: $0 create example.com 9000"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Default starting port
|
||||||
|
port=${port:-9000}
|
||||||
|
|
||||||
|
local domain_dir=$(get_domain_dir "$domain")
|
||||||
|
|
||||||
|
if [ -d "$domain_dir" ]; then
|
||||||
|
log_warn "Domain '$domain' already exists at $domain_dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Creating domain: $domain"
|
||||||
|
|
||||||
|
# Create directory structure
|
||||||
|
mkdir -p "$domain_dir"/{www,data,config}
|
||||||
|
|
||||||
|
# Create compose.yaml template
|
||||||
|
cat > "$domain_dir/compose.yaml" << EOF
|
||||||
|
# Compose file for $domain
|
||||||
|
# All services bind to 127.0.0.1 only (routed via nginx reverse proxy)
|
||||||
|
#
|
||||||
|
# Port assignments for $domain:
|
||||||
|
# - Main site ($domain): $port
|
||||||
|
# - API (api.$domain): $((port + 1))
|
||||||
|
# - Add more subdomains as needed
|
||||||
|
#
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Main website
|
||||||
|
www:
|
||||||
|
image: docker.io/nginx:stable-alpine
|
||||||
|
container_name: ${domain//./-}-www
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:${port}:80"
|
||||||
|
volumes:
|
||||||
|
- ./www:/usr/share/nginx/html:ro
|
||||||
|
# healthcheck:
|
||||||
|
# test: ["CMD", "curl", "-f", "http://localhost/"]
|
||||||
|
# interval: 30s
|
||||||
|
# timeout: 10s
|
||||||
|
# retries: 3
|
||||||
|
|
||||||
|
# Uncomment to add API subdomain
|
||||||
|
# api:
|
||||||
|
# image: your-api-image
|
||||||
|
# container_name: ${domain//./-}-api
|
||||||
|
# restart: unless-stopped
|
||||||
|
# ports:
|
||||||
|
# - "127.0.0.1:$((port + 1)):8080"
|
||||||
|
# volumes:
|
||||||
|
# - ./data:/app/data
|
||||||
|
# environment:
|
||||||
|
# - NODE_ENV=production
|
||||||
|
|
||||||
|
# Shared network (optional)
|
||||||
|
# networks:
|
||||||
|
# default:
|
||||||
|
# name: ${domain//./-}-network
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create default index.html
|
||||||
|
cat > "$domain_dir/www/index.html" << EOF
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Welcome to $domain</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>$domain</h1>
|
||||||
|
<p>Your site is ready to be configured.</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create README
|
||||||
|
cat > "$domain_dir/README.md" << EOF
|
||||||
|
# $domain
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
\`\`\`
|
||||||
|
$domain/
|
||||||
|
├── compose.yaml # Podman compose configuration
|
||||||
|
├── www/ # Static website files
|
||||||
|
├── data/ # Persistent data volumes
|
||||||
|
├── config/ # Configuration files
|
||||||
|
└── README.md # This file
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Port Assignment
|
||||||
|
|
||||||
|
- Main site ($domain): \`127.0.0.1:$port\`
|
||||||
|
- API (api.$domain): \`127.0.0.1:$((port + 1))\` (if enabled)
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
# Start the domain
|
||||||
|
hostctl start $domain
|
||||||
|
|
||||||
|
# Stop the domain
|
||||||
|
hostctl stop $domain
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
hostctl logs $domain
|
||||||
|
|
||||||
|
# Check status
|
||||||
|
hostctl status $domain
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Nginx Configuration
|
||||||
|
|
||||||
|
After starting the containers, add nginx configuration:
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
sudo /docker/www/startup.sh add-domain $domain $port
|
||||||
|
\`\`\`
|
||||||
|
EOF
|
||||||
|
|
||||||
|
log_success "Domain created: $domain_dir"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo " 1. Edit $domain_dir/compose.yaml to configure services"
|
||||||
|
echo " 2. Add your website files to $domain_dir/www/"
|
||||||
|
echo " 3. Start with: $0 start $domain"
|
||||||
|
echo " 4. Add nginx config: sudo /docker/www/startup.sh add-domain $domain $port"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remove a domain
|
||||||
|
remove_domain() {
|
||||||
|
local domain=$1
|
||||||
|
local force=$2
|
||||||
|
|
||||||
|
if [ -z "$domain" ]; then
|
||||||
|
log_error "Usage: $0 remove <domain> [--force]"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! domain_exists "$domain"; then
|
||||||
|
log_error "Domain '$domain' not found."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local domain_dir=$(get_domain_dir "$domain")
|
||||||
|
|
||||||
|
# Check if running
|
||||||
|
cd "$domain_dir"
|
||||||
|
if [ "$(podman-compose ps -q 2>/dev/null | wc -l)" -gt 0 ]; then
|
||||||
|
if [ "$force" != "--force" ]; then
|
||||||
|
log_error "Domain '$domain' is running. Stop it first or use --force"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
log_warn "Force stopping $domain..."
|
||||||
|
podman-compose down
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$force" != "--force" ]; then
|
||||||
|
echo -n "Are you sure you want to remove $domain? This will delete all files! (y/N) "
|
||||||
|
read -r confirm
|
||||||
|
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
||||||
|
log_info "Cancelled."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf "$domain_dir"
|
||||||
|
log_success "Domain '$domain' removed."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Start all domains
|
||||||
|
start_all() {
|
||||||
|
log_header "Starting All Domains"
|
||||||
|
|
||||||
|
for domain_dir in "$DOMAINS_DIR"/*/; do
|
||||||
|
if [ -d "$domain_dir" ] && [ -f "$domain_dir/compose.yaml" ]; then
|
||||||
|
domain=$(basename "$domain_dir")
|
||||||
|
start_domain "$domain"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
log_success "All domains started"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Stop all domains
|
||||||
|
stop_all() {
|
||||||
|
log_header "Stopping All Domains"
|
||||||
|
|
||||||
|
for domain_dir in "$DOMAINS_DIR"/*/; do
|
||||||
|
if [ -d "$domain_dir" ] && [ -f "$domain_dir/compose.yaml" ]; then
|
||||||
|
domain=$(basename "$domain_dir")
|
||||||
|
stop_domain "$domain"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
log_success "All domains stopped"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show usage
|
||||||
|
usage() {
|
||||||
|
echo "Web Host Management Script"
|
||||||
|
echo ""
|
||||||
|
echo "Usage: $0 <command> [options]"
|
||||||
|
echo ""
|
||||||
|
echo "Commands:"
|
||||||
|
echo " list List all configured domains"
|
||||||
|
echo " status [domain] Show status (all or specific domain)"
|
||||||
|
echo " start <domain> Start a domain"
|
||||||
|
echo " stop <domain> Stop a domain"
|
||||||
|
echo " restart <domain> Restart a domain"
|
||||||
|
echo " logs <domain> [svc] View logs for a domain"
|
||||||
|
echo ""
|
||||||
|
echo " create <domain> [port] Create a new domain (default port: 9000)"
|
||||||
|
echo " remove <domain> Remove a domain"
|
||||||
|
echo ""
|
||||||
|
echo " start-all Start all domains"
|
||||||
|
echo " stop-all Stop all domains"
|
||||||
|
echo ""
|
||||||
|
echo "Examples:"
|
||||||
|
echo " $0 create example.com 9000"
|
||||||
|
echo " $0 start example.com"
|
||||||
|
echo " $0 logs example.com www"
|
||||||
|
echo " $0 status"
|
||||||
|
echo ""
|
||||||
|
echo "Directory structure:"
|
||||||
|
echo " $DOMAINS_DIR/<domain>/compose.yaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main entry point
|
||||||
|
case "${1:-help}" in
|
||||||
|
list)
|
||||||
|
list_domains
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
status_domain "$2"
|
||||||
|
;;
|
||||||
|
start)
|
||||||
|
start_domain "$2"
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
stop_domain "$2"
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
restart_domain "$2"
|
||||||
|
;;
|
||||||
|
logs)
|
||||||
|
logs_domain "$2" "$3"
|
||||||
|
;;
|
||||||
|
create)
|
||||||
|
create_domain "$2" "$3"
|
||||||
|
;;
|
||||||
|
remove|delete)
|
||||||
|
remove_domain "$2" "$3"
|
||||||
|
;;
|
||||||
|
start-all)
|
||||||
|
start_all
|
||||||
|
;;
|
||||||
|
stop-all)
|
||||||
|
stop_all
|
||||||
|
;;
|
||||||
|
help|--help|-h|"")
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_error "Unknown command: $1"
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Reference in New Issue
Block a user