diff --git a/Documentation/MikrusVPSDeployment.md b/Documentation/MikrusVPSDeployment.md new file mode 100644 index 0000000..1a1e51a --- /dev/null +++ b/Documentation/MikrusVPSDeployment.md @@ -0,0 +1,478 @@ +# Mikrus VPS Deployment Guide for TheOfficeAPI + +This guide explains how to deploy TheOfficeAPI to a Mikrus VPS (mikrus.us) server. + +## Which Mikrus VPS to Choose + +### Recommended VPS Plans + +For TheOfficeAPI (.NET 9.0 application with Docker), here are the recommended plans: + +#### **Minimum Requirements (Budget Option)** +- **Mikrus VPS S** or **VPS M** + - RAM: 512MB - 1GB + - CPU: 1 core + - Disk: 10GB SSD + - Cost: ~5-10 PLN/month + - **Best for**: Testing, development, low-traffic demos + +#### **Recommended for Production (Best Value)** +- **Mikrus VPS L** or **VPS XL** + - RAM: 2-4GB + - CPU: 2+ cores + - Disk: 20-40GB SSD + - Cost: ~15-25 PLN/month + - **Best for**: Production deployment, medium traffic + - **Why**: .NET applications can be memory-intensive, especially with Docker overhead + +#### **High Performance Option** +- **Mikrus VPS XXL** or higher + - RAM: 8GB+ + - CPU: 4+ cores + - Disk: 80GB+ SSD + - Cost: ~40+ PLN/month + - **Best for**: High-traffic production, multiple services + +### What to Look For + +When selecting a Mikrus VPS, ensure it has: +- ✅ **Docker support** (most Mikrus VPS plans support Docker) +- ✅ **Public IPv4 address** (for external access) +- ✅ **SSH access** (for deployment) +- ✅ **Linux OS** (Ubuntu 22.04 or Debian 11+ recommended) +- ✅ **At least 1GB RAM** (for .NET + Docker) + +## Prerequisites + +Before deploying, ensure you have: +- Mikrus VPS account and active server +- SSH access to your VPS +- Domain name (optional, but recommended) +- Basic Linux command-line knowledge + +## Deployment Steps + +### 1. Connect to Your Mikrus VPS + +```bash +# Replace with your Mikrus VPS IP and username +ssh user@your-vps-ip + +# Or if you have a specific port +ssh -p 2222 user@your-vps-ip +``` + +### 2. Install Docker and Docker Compose + +```bash +# Update system packages +sudo apt update && sudo apt upgrade -y + +# Install Docker +sudo apt install -y apt-transport-https ca-certificates curl software-properties-common +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg +echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null +sudo apt update +sudo apt install -y docker-ce docker-ce-cli containerd.io + +# Install Docker Compose +sudo apt install -y docker-compose-plugin + +# Verify installation +docker --version +docker compose version + +# Add your user to docker group (to run docker without sudo) +sudo usermod -aG docker $USER +newgrp docker +``` + +### 3. Install Git + +```bash +sudo apt install -y git +git --version +``` + +### 4. Clone the Repository + +```bash +# Clone the project +cd ~ +git clone https://github.com/fszymaniak/TheOfficeAPI.git +cd TheOfficeAPI + +# Or if you need a specific branch +git checkout main +``` + +### 5. Configure the Application + +Create a production environment configuration: + +```bash +# Create a .env file for production settings +cat > .env << 'EOF' +ASPNETCORE_ENVIRONMENT=Production +MATURITY_LEVEL=Level0 +PORT=8080 +ASPNETCORE_URLS=http://+:8080 +EOF +``` + +### 6. Build and Deploy with Docker + +#### Option A: Using Docker Compose (Recommended) + +```bash +# Build and start the container +docker compose up -d --build + +# View logs +docker compose logs -f theofficeapi-level0 + +# Check container status +docker compose ps +``` + +#### Option B: Using Docker Directly + +```bash +# Build the Docker image +docker build -t theofficeapi:latest . + +# Run the container +docker run -d \ + --name theofficeapi \ + --restart unless-stopped \ + -p 8080:8080 \ + -e ASPNETCORE_ENVIRONMENT=Production \ + -e MATURITY_LEVEL=Level0 \ + theofficeapi:latest + +# View logs +docker logs -f theofficeapi + +# Check container status +docker ps +``` + +### 7. Configure Nginx Reverse Proxy (Recommended) + +For production deployment, use Nginx as a reverse proxy: + +```bash +# Install Nginx +sudo apt install -y nginx + +# Create Nginx configuration +sudo nano /etc/nginx/sites-available/theofficeapi +``` + +Add the following configuration: + +```nginx +server { + listen 80; + server_name your-domain.com www.your-domain.com; # Replace with your domain + + location / { + proxy_pass http://localhost:8080; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection keep-alive; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + # Health check endpoint + location /health { + proxy_pass http://localhost:8080/health; + access_log off; + } +} +``` + +Enable the site and restart Nginx: + +```bash +# Enable the site +sudo ln -s /etc/nginx/sites-available/theofficeapi /etc/nginx/sites-enabled/ + +# Test Nginx configuration +sudo nginx -t + +# Restart Nginx +sudo systemctl restart nginx +sudo systemctl enable nginx +``` + +### 8. Configure SSL with Let's Encrypt (Optional but Recommended) + +```bash +# Install Certbot +sudo apt install -y certbot python3-certbot-nginx + +# Obtain SSL certificate +sudo certbot --nginx -d your-domain.com -d www.your-domain.com + +# Test automatic renewal +sudo certbot renew --dry-run +``` + +### 9. Configure Firewall + +```bash +# Allow SSH, HTTP, and HTTPS +sudo ufw allow 22/tcp +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp + +# Enable firewall +sudo ufw enable +sudo ufw status +``` + +## Verification + +### 1. Check if the Application is Running + +```bash +# Check Docker container status +docker ps + +# View application logs +docker logs theofficeapi + +# Or with docker-compose +docker compose logs theofficeapi-level0 +``` + +### 2. Test the API Endpoints + +```bash +# Test health endpoint +curl http://localhost:8080/health + +# Test API Level 0 endpoint +curl -X POST http://localhost:8080/api/theOffice \ + -H "Content-Type: application/json" \ + -d '{"action":"getAllSeasons"}' + +# Test from external access (replace with your domain or IP) +curl http://your-domain.com/health +``` + +### 3. Access Swagger UI + +Open your browser and navigate to: +- Local: `http://your-vps-ip:8080/swagger` +- With domain: `http://your-domain.com/swagger` +- With SSL: `https://your-domain.com/swagger` + +### 4. Monitor Application + +```bash +# Check CPU and memory usage +docker stats + +# View real-time logs +docker logs -f theofficeapi + +# Check Nginx access logs +sudo tail -f /var/log/nginx/access.log +``` + +## Maintenance + +### Updating the Application + +```bash +# Pull latest changes +cd ~/TheOfficeAPI +git pull origin main + +# Rebuild and restart containers +docker compose down +docker compose up -d --build + +# Or with Docker directly +docker stop theofficeapi +docker rm theofficeapi +docker build -t theofficeapi:latest . +docker run -d \ + --name theofficeapi \ + --restart unless-stopped \ + -p 8080:8080 \ + -e ASPNETCORE_ENVIRONMENT=Production \ + -e MATURITY_LEVEL=Level0 \ + theofficeapi:latest +``` + +### Backup and Restore + +```bash +# Export Docker image +docker save theofficeapi:latest | gzip > theofficeapi-backup.tar.gz + +# Import Docker image +docker load < theofficeapi-backup.tar.gz +``` + +### View Logs + +```bash +# Docker logs +docker logs theofficeapi --tail 100 -f + +# Nginx logs +sudo tail -f /var/log/nginx/access.log +sudo tail -f /var/log/nginx/error.log +``` + +## Troubleshooting + +### Container Won't Start + +```bash +# Check Docker logs +docker logs theofficeapi + +# Check if port is already in use +sudo netstat -tulpn | grep 8080 + +# Remove and recreate container +docker rm -f theofficeapi +docker compose up -d --force-recreate +``` + +### High Memory Usage + +```bash +# Check memory usage +free -h +docker stats + +# Set memory limits in docker-compose.yaml +# Add under service configuration: +# mem_limit: 512m +# mem_reservation: 256m +``` + +### Connection Issues + +```bash +# Check firewall +sudo ufw status + +# Check if application is listening +sudo netstat -tulpn | grep 8080 + +# Check Nginx configuration +sudo nginx -t +sudo systemctl status nginx +``` + +## Performance Optimization + +### 1. Enable Docker Logging Limits + +Add to `docker-compose.yaml`: + +```yaml +services: + theofficeapi-level0: + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" +``` + +### 2. Configure Nginx Caching + +Add to Nginx configuration: + +```nginx +# Add inside http block in /etc/nginx/nginx.conf +proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m max_size=100m inactive=60m; + +# Add inside location block +proxy_cache api_cache; +proxy_cache_valid 200 5m; +proxy_cache_bypass $http_cache_control; +add_header X-Cache-Status $upstream_cache_status; +``` + +### 3. Enable Compression + +Nginx already has compression enabled by default for common content types. + +## Security Best Practices + +1. **Keep system updated**: + ```bash + sudo apt update && sudo apt upgrade -y + ``` + +2. **Use strong SSH keys** (disable password authentication) + +3. **Enable automatic security updates**: + ```bash + sudo apt install -y unattended-upgrades + sudo dpkg-reconfigure -plow unattended-upgrades + ``` + +4. **Monitor application logs** regularly + +5. **Use environment variables** for sensitive configuration (never commit secrets) + +6. **Enable SSL/TLS** with Let's Encrypt + +7. **Set up fail2ban** to prevent brute force attacks: + ```bash + sudo apt install -y fail2ban + sudo systemctl enable fail2ban + sudo systemctl start fail2ban + ``` + +## Cost Estimation + +Based on Mikrus VPS pricing (approximate): + +| Plan | RAM | CPU | Disk | Monthly Cost | Suitable For | +|------|-----|-----|------|--------------|--------------| +| VPS S | 512MB | 1 core | 10GB | ~5 PLN | Testing only | +| VPS M | 1GB | 1 core | 15GB | ~10 PLN | Light traffic | +| VPS L | 2GB | 2 cores | 20GB | ~15 PLN | **Recommended** | +| VPS XL | 4GB | 2 cores | 40GB | ~25 PLN | Production | +| VPS XXL | 8GB | 4 cores | 80GB | ~40 PLN | High traffic | + +*Note: Prices are approximate and may vary. Check mikrus.us for current pricing.* + +## Support and Resources + +- **Mikrus Support**: https://mikrus.us/ +- **TheOfficeAPI GitHub**: https://github.com/fszymaniak/TheOfficeAPI +- **Docker Documentation**: https://docs.docker.com/ +- **Nginx Documentation**: https://nginx.org/en/docs/ + +## Next Steps + +1. Choose appropriate VPS plan based on expected traffic +2. Set up domain name (optional) +3. Configure monitoring and alerting +4. Set up automated backups +5. Implement CI/CD pipeline for automatic deployments + +For additional deployment options, see: +- [Railway Deployment](RailwayDeployment.md) +- [Docker Setup](DockerSetup.md) diff --git a/README.md b/README.md index a8255cd..7c4b7b9 100644 --- a/README.md +++ b/README.md @@ -305,6 +305,23 @@ MATURITY_LEVEL=Level3 dotnet run --project src/TheOfficeAPI ## Deployment +### Mikrus VPS (mikrus.us) + +Deploy to your own Mikrus VPS server with full control. This option provides: +- Complete server control and customization +- Cost-effective hosting (starting from ~10 PLN/month) +- Docker-based deployment with Nginx reverse proxy +- SSL/TLS support with Let's Encrypt +- Ideal for production deployments + +**Quick Deploy:** +```bash +# On your Mikrus VPS +curl -fsSL https://raw.githubusercontent.com/fszymaniak/TheOfficeAPI/main/scripts/deploy-mikrus.sh | bash +``` + +For detailed instructions, see [Documentation/MikrusVPSDeployment.md](Documentation/MikrusVPSDeployment.md). + ### Railway The application is configured for deployment on Railway. It automatically: diff --git a/scripts/deploy-mikrus.sh b/scripts/deploy-mikrus.sh new file mode 100755 index 0000000..6f76a53 --- /dev/null +++ b/scripts/deploy-mikrus.sh @@ -0,0 +1,365 @@ +#!/bin/bash + +# TheOfficeAPI - Mikrus VPS Quick Deployment Script +# This script automates the deployment process on a Mikrus VPS + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuration +REPO_URL="${REPO_URL:-https://github.com/fszymaniak/TheOfficeAPI.git}" +REPO_DIR="${REPO_DIR:-$HOME/TheOfficeAPI}" +BRANCH="${BRANCH:-main}" +APP_PORT="${APP_PORT:-8080}" +MATURITY_LEVEL="${MATURITY_LEVEL:-Level0}" + +# Function to print colored output +print_header() { + echo "" + echo -e "${BLUE}======================================" + echo -e "$1" + echo -e "======================================${NC}" + echo "" +} + +print_success() { + echo -e "${GREEN}✓${NC} $1" +} + +print_error() { + echo -e "${RED}✗${NC} $1" +} + +print_info() { + echo -e "${YELLOW}ℹ${NC} $1" +} + +# Function to check if command exists +command_exists() { + command -v "$1" &> /dev/null +} + +# Function to install Docker +install_docker() { + print_header "Installing Docker" + + if command_exists docker; then + print_success "Docker is already installed" + docker --version + return 0 + fi + + print_info "Installing Docker..." + + # Update package index + sudo apt-get update + + # Install prerequisites + sudo apt-get install -y \ + apt-transport-https \ + ca-certificates \ + curl \ + gnupg \ + lsb-release \ + software-properties-common + + # Add Docker's official GPG key + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg + + # Set up the stable repository + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + + # Install Docker Engine + sudo apt-get update + sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin + + # Add current user to docker group + sudo usermod -aG docker $USER + + print_success "Docker installed successfully" + docker --version + + print_info "You may need to log out and back in for docker group changes to take effect" +} + +# Function to install Git +install_git() { + print_header "Checking Git Installation" + + if command_exists git; then + print_success "Git is already installed" + git --version + return 0 + fi + + print_info "Installing Git..." + sudo apt-get update + sudo apt-get install -y git + + print_success "Git installed successfully" + git --version +} + +# Function to clone or update repository +setup_repository() { + print_header "Setting Up Repository" + + if [ -d "$REPO_DIR" ]; then + print_info "Repository directory already exists. Updating..." + cd "$REPO_DIR" + git fetch origin + git checkout "$BRANCH" + git pull origin "$BRANCH" + print_success "Repository updated" + else + print_info "Cloning repository..." + git clone "$REPO_URL" "$REPO_DIR" + cd "$REPO_DIR" + git checkout "$BRANCH" + print_success "Repository cloned" + fi + + print_info "Current directory: $(pwd)" + print_info "Current branch: $(git branch --show-current)" +} + +# Function to create environment file +create_env_file() { + print_header "Creating Environment Configuration" + + cd "$REPO_DIR" + + cat > .env << EOF +ASPNETCORE_ENVIRONMENT=Production +MATURITY_LEVEL=$MATURITY_LEVEL +PORT=$APP_PORT +ASPNETCORE_URLS=http://+:$APP_PORT +EOF + + print_success "Environment file created" + cat .env +} + +# Function to stop existing containers +stop_existing_containers() { + print_header "Stopping Existing Containers" + + cd "$REPO_DIR" + + if docker compose ps -q theofficeapi-level0 &> /dev/null; then + print_info "Stopping containers via docker-compose..." + docker compose down + print_success "Containers stopped" + elif docker ps -a | grep -q theofficeapi; then + print_info "Stopping containers via docker..." + docker stop theofficeapi 2>/dev/null || true + docker rm theofficeapi 2>/dev/null || true + print_success "Containers stopped" + else + print_info "No existing containers to stop" + fi +} + +# Function to build and start containers +deploy_application() { + print_header "Building and Deploying Application" + + cd "$REPO_DIR" + + print_info "Building Docker image..." + docker compose build --no-cache + + print_info "Starting containers..." + docker compose up -d + + print_success "Application deployed successfully" +} + +# Function to show deployment info +show_deployment_info() { + print_header "Deployment Information" + + echo "Container Status:" + docker compose ps + + echo "" + echo "Container Logs (last 20 lines):" + docker compose logs --tail 20 theofficeapi-level0 + + echo "" + print_success "Deployment completed!" + echo "" + print_info "Access your application:" + echo " - Health Check: http://localhost:$APP_PORT/health" + echo " - Swagger UI: http://localhost:$APP_PORT/swagger" + echo " - API Endpoint: http://localhost:$APP_PORT/api/theOffice" + echo "" + print_info "Useful commands:" + echo " - View logs: docker compose logs -f theofficeapi-level0" + echo " - Stop app: docker compose down" + echo " - Restart app: docker compose restart" + echo " - Verify deployment: ./scripts/verify-deployment.sh" +} + +# Function to setup Nginx (optional) +setup_nginx() { + print_header "Nginx Setup (Optional)" + + read -p "Do you want to install and configure Nginx as reverse proxy? (y/n): " -n 1 -r + echo + + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + print_info "Skipping Nginx setup" + return 0 + fi + + if ! command_exists nginx; then + print_info "Installing Nginx..." + sudo apt-get update + sudo apt-get install -y nginx + fi + + print_success "Nginx is installed" + + read -p "Enter your domain name (or press Enter to skip): " DOMAIN_NAME + + if [ -z "$DOMAIN_NAME" ]; then + print_info "Skipping Nginx configuration" + return 0 + fi + + print_info "Creating Nginx configuration for $DOMAIN_NAME..." + + sudo tee /etc/nginx/sites-available/theofficeapi > /dev/null << EOF +server { + listen 80; + server_name $DOMAIN_NAME www.$DOMAIN_NAME; + + location / { + proxy_pass http://localhost:$APP_PORT; + proxy_http_version 1.1; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection keep-alive; + proxy_set_header Host \$host; + proxy_cache_bypass \$http_upgrade; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_set_header X-Real-IP \$remote_addr; + + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + location /health { + proxy_pass http://localhost:$APP_PORT/health; + access_log off; + } +} +EOF + + # Enable site + sudo ln -sf /etc/nginx/sites-available/theofficeapi /etc/nginx/sites-enabled/ + + # Test configuration + if sudo nginx -t; then + print_success "Nginx configuration is valid" + sudo systemctl restart nginx + sudo systemctl enable nginx + print_success "Nginx configured and restarted" + + echo "" + print_info "Your application is now accessible at: http://$DOMAIN_NAME" + echo "" + print_info "To enable SSL/HTTPS, run:" + echo " sudo apt-get install -y certbot python3-certbot-nginx" + echo " sudo certbot --nginx -d $DOMAIN_NAME -d www.$DOMAIN_NAME" + else + print_error "Nginx configuration has errors" + sudo nginx -t + fi +} + +# Function to setup firewall +setup_firewall() { + print_header "Firewall Setup (Optional)" + + read -p "Do you want to configure UFW firewall? (y/n): " -n 1 -r + echo + + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + print_info "Skipping firewall setup" + return 0 + fi + + if ! command_exists ufw; then + print_info "Installing UFW..." + sudo apt-get update + sudo apt-get install -y ufw + fi + + print_info "Configuring firewall rules..." + sudo ufw allow 22/tcp comment 'SSH' + sudo ufw allow 80/tcp comment 'HTTP' + sudo ufw allow 443/tcp comment 'HTTPS' + + print_info "Enabling firewall..." + sudo ufw --force enable + + print_success "Firewall configured" + sudo ufw status +} + +# Main execution +main() { + print_header "TheOfficeAPI - Mikrus VPS Deployment" + + print_info "Starting deployment with the following configuration:" + echo " Repository: $REPO_URL" + echo " Branch: $BRANCH" + echo " Directory: $REPO_DIR" + echo " Port: $APP_PORT" + echo " Maturity Level: $MATURITY_LEVEL" + echo "" + + # Check if running as root + if [ "$EUID" -eq 0 ]; then + print_error "Please do not run this script as root. Run as a regular user with sudo privileges." + exit 1 + fi + + # Install dependencies + install_git + install_docker + + # Setup and deploy + setup_repository + create_env_file + stop_existing_containers + deploy_application + show_deployment_info + + # Optional components + setup_nginx + setup_firewall + + print_header "Deployment Complete!" + + echo "" + print_success "Your TheOfficeAPI is now running!" + echo "" + print_info "Next steps:" + echo " 1. Verify deployment: ./scripts/verify-deployment.sh" + echo " 2. Check logs: docker compose logs -f theofficeapi-level0" + echo " 3. Access Swagger UI: http://your-server-ip:$APP_PORT/swagger" + echo "" +} + +# Run main function +main diff --git a/scripts/verify-deployment.sh b/scripts/verify-deployment.sh new file mode 100755 index 0000000..3e4dfae --- /dev/null +++ b/scripts/verify-deployment.sh @@ -0,0 +1,361 @@ +#!/bin/bash + +# TheOfficeAPI - Mikrus VPS Deployment Verification Script +# This script verifies that the application is properly deployed and running + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Configuration +APP_PORT="${APP_PORT:-8080}" +APP_HOST="${APP_HOST:-localhost}" +CONTAINER_NAME="${CONTAINER_NAME:-theofficeapi}" + +echo "======================================" +echo "TheOfficeAPI Deployment Verification" +echo "======================================" +echo "" + +# Function to print success message +success() { + echo -e "${GREEN}✓${NC} $1" +} + +# Function to print error message +error() { + echo -e "${RED}✗${NC} $1" +} + +# Function to print warning message +warning() { + echo -e "${YELLOW}⚠${NC} $1" +} + +# Function to print info message +info() { + echo -e "${YELLOW}ℹ${NC} $1" +} + +# Check if Docker is installed +check_docker() { + echo "Checking Docker installation..." + if command -v docker &> /dev/null; then + DOCKER_VERSION=$(docker --version) + success "Docker is installed: $DOCKER_VERSION" + return 0 + else + error "Docker is not installed" + return 1 + fi +} + +# Check if Docker Compose is installed +check_docker_compose() { + echo "Checking Docker Compose installation..." + if docker compose version &> /dev/null; then + COMPOSE_VERSION=$(docker compose version) + success "Docker Compose is installed: $COMPOSE_VERSION" + return 0 + else + warning "Docker Compose (plugin) is not installed" + return 1 + fi +} + +# Check if container is running +check_container() { + echo "" + echo "Checking if container is running..." + + # Try docker-compose first + if docker compose ps 2>/dev/null | grep -q "theofficeapi"; then + success "Container is running (via docker-compose)" + docker compose ps + return 0 + fi + + # Try direct docker command + if docker ps | grep -q "$CONTAINER_NAME"; then + success "Container is running (via docker)" + docker ps --filter "name=$CONTAINER_NAME" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" + return 0 + else + error "Container is not running" + info "Checking all containers:" + docker ps -a + return 1 + fi +} + +# Check container logs for errors +check_container_logs() { + echo "" + echo "Checking container logs for errors..." + + # Try to get logs + if docker logs --tail 50 "$CONTAINER_NAME" 2>/dev/null | grep -i "error\|exception\|fail" > /tmp/errors.log; then + warning "Found potential errors in logs:" + cat /tmp/errors.log + rm /tmp/errors.log + else + success "No obvious errors in recent logs" + fi + + echo "" + info "Last 10 lines of logs:" + docker logs --tail 10 "$CONTAINER_NAME" 2>&1 || docker compose logs --tail 10 theofficeapi-level0 2>&1 +} + +# Check if application is responding +check_application_health() { + echo "" + echo "Checking application health..." + + # Wait a moment for the app to be ready + sleep 2 + + # Check health endpoint + if curl -f -s -m 5 "http://${APP_HOST}:${APP_PORT}/health" > /dev/null; then + success "Health endpoint is responding" + HEALTH_RESPONSE=$(curl -s "http://${APP_HOST}:${APP_PORT}/health") + echo "Response: $HEALTH_RESPONSE" + return 0 + else + error "Health endpoint is not responding" + return 1 + fi +} + +# Test API Level 0 endpoint +check_api_level0() { + echo "" + echo "Testing API Level 0 endpoint..." + + RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "http://${APP_HOST}:${APP_PORT}/api/theOffice" \ + -H "Content-Type: application/json" \ + -d '{"action":"getAllSeasons"}' 2>&1) + + HTTP_CODE=$(echo "$RESPONSE" | tail -n1) + BODY=$(echo "$RESPONSE" | head -n-1) + + if [ "$HTTP_CODE" = "200" ]; then + success "API Level 0 is working (HTTP $HTTP_CODE)" + echo "Response preview (first 200 chars):" + echo "$BODY" | head -c 200 + echo "..." + return 0 + else + error "API Level 0 failed (HTTP $HTTP_CODE)" + echo "Response: $BODY" + return 1 + fi +} + +# Check Swagger UI +check_swagger() { + echo "" + echo "Checking Swagger UI..." + + if curl -f -s -m 5 "http://${APP_HOST}:${APP_PORT}/swagger" > /dev/null; then + success "Swagger UI is accessible at http://${APP_HOST}:${APP_PORT}/swagger" + return 0 + else + warning "Swagger UI may not be accessible (check if enabled in production)" + return 1 + fi +} + +# Check port accessibility +check_port() { + echo "" + echo "Checking if port $APP_PORT is accessible..." + + if command -v netstat &> /dev/null; then + if netstat -tuln | grep -q ":$APP_PORT "; then + success "Port $APP_PORT is listening" + netstat -tuln | grep ":$APP_PORT " + return 0 + else + error "Port $APP_PORT is not listening" + return 1 + fi + elif command -v ss &> /dev/null; then + if ss -tuln | grep -q ":$APP_PORT "; then + success "Port $APP_PORT is listening" + ss -tuln | grep ":$APP_PORT " + return 0 + else + error "Port $APP_PORT is not listening" + return 1 + fi + else + warning "Neither netstat nor ss is available, skipping port check" + return 1 + fi +} + +# Check system resources +check_resources() { + echo "" + echo "Checking system resources..." + + # Memory + if command -v free &> /dev/null; then + echo "" + echo "Memory usage:" + free -h + fi + + # Docker stats + echo "" + echo "Docker container resources (5 second snapshot):" + timeout 5 docker stats --no-stream "$CONTAINER_NAME" 2>/dev/null || \ + timeout 5 docker stats --no-stream 2>/dev/null | grep -i "theoffice" || \ + warning "Could not get container stats" +} + +# Check Nginx (if installed) +check_nginx() { + echo "" + echo "Checking Nginx configuration..." + + if command -v nginx &> /dev/null; then + success "Nginx is installed" + + if systemctl is-active --quiet nginx; then + success "Nginx is running" + else + warning "Nginx is installed but not running" + fi + + # Test configuration + if sudo nginx -t &> /dev/null; then + success "Nginx configuration is valid" + else + error "Nginx configuration has errors" + sudo nginx -t + fi + else + info "Nginx is not installed (optional)" + fi +} + +# Check SSL certificate (if Let's Encrypt is used) +check_ssl() { + echo "" + echo "Checking SSL certificate..." + + if command -v certbot &> /dev/null; then + success "Certbot is installed" + + CERTS=$(sudo certbot certificates 2>/dev/null) + if [ -n "$CERTS" ]; then + success "SSL certificates found:" + echo "$CERTS" + else + info "No SSL certificates found" + fi + else + info "Certbot is not installed (optional for SSL)" + fi +} + +# Check firewall +check_firewall() { + echo "" + echo "Checking firewall configuration..." + + if command -v ufw &> /dev/null; then + UFW_STATUS=$(sudo ufw status 2>/dev/null) + if echo "$UFW_STATUS" | grep -q "Status: active"; then + success "UFW firewall is active" + echo "$UFW_STATUS" | grep -E "80|443|8080" + else + warning "UFW firewall is not active" + fi + else + info "UFW is not installed" + fi +} + +# Generate summary report +generate_summary() { + echo "" + echo "======================================" + echo "Deployment Verification Summary" + echo "======================================" + echo "" + + TOTAL_CHECKS=0 + PASSED_CHECKS=0 + + echo "Core Services:" + [ $DOCKER_INSTALLED -eq 0 ] && success "Docker" && ((PASSED_CHECKS++)) || error "Docker" + ((TOTAL_CHECKS++)) + + [ $CONTAINER_RUNNING -eq 0 ] && success "Container" && ((PASSED_CHECKS++)) || error "Container" + ((TOTAL_CHECKS++)) + + [ $APP_HEALTH -eq 0 ] && success "Health Check" && ((PASSED_CHECKS++)) || error "Health Check" + ((TOTAL_CHECKS++)) + + [ $API_WORKING -eq 0 ] && success "API Endpoint" && ((PASSED_CHECKS++)) || error "API Endpoint" + ((TOTAL_CHECKS++)) + + echo "" + echo "Score: $PASSED_CHECKS/$TOTAL_CHECKS checks passed" + echo "" + + if [ $PASSED_CHECKS -eq $TOTAL_CHECKS ]; then + success "All core checks passed! Deployment is healthy." + echo "" + info "Access your API at:" + echo " - Swagger UI: http://${APP_HOST}:${APP_PORT}/swagger" + echo " - Health Check: http://${APP_HOST}:${APP_PORT}/health" + echo " - API Endpoint: http://${APP_HOST}:${APP_PORT}/api/theOffice" + return 0 + else + error "Some checks failed. Please review the errors above." + return 1 + fi +} + +# Main execution +main() { + DOCKER_INSTALLED=1 + CONTAINER_RUNNING=1 + APP_HEALTH=1 + API_WORKING=1 + + check_docker && DOCKER_INSTALLED=0 || DOCKER_INSTALLED=1 + check_docker_compose + + if [ $DOCKER_INSTALLED -eq 0 ]; then + check_container && CONTAINER_RUNNING=0 || CONTAINER_RUNNING=1 + + if [ $CONTAINER_RUNNING -eq 0 ]; then + check_container_logs + check_port + check_application_health && APP_HEALTH=0 || APP_HEALTH=1 + check_api_level0 && API_WORKING=0 || API_WORKING=1 + check_swagger + check_resources + fi + fi + + check_nginx + check_ssl + check_firewall + + generate_summary + + exit $? +} + +# Run main function +main