#!/bin/bash # Comprehensive fix for Waitress port parsing issue on VPS set -e echo "=== Fixing Waitress Port Parsing Issue ===" echo APP_DIR="/opt/mockapi" SERVICE_FILE="/etc/systemd/system/mockapi.service" ENV_FILE="${APP_DIR}/.env" print_status() { echo -e "\033[0;32m[+]\033[0m $1" } print_warning() { echo -e "\033[1;33m[!]\033[0m $1" } print_error() { echo -e "\033[0;31m[!]\033[0m $1" } # Step 1: Check environment print_status "Step 1: Checking environment" if [[ ! -d "$APP_DIR" ]]; then print_error "Application directory not found: $APP_DIR" exit 1 fi if [[ ! -f "$SERVICE_FILE" ]]; then print_error "Service file not found: $SERVICE_FILE" exit 1 fi cd "$APP_DIR" # Step 2: Read current port from .env print_status "Step 2: Reading current configuration" PORT="8000" HOST="0.0.0.0" if [[ -f "$ENV_FILE" ]]; then if grep -q "^PORT=" "$ENV_FILE"; then PORT=$(grep "^PORT=" "$ENV_FILE" | cut -d'=' -f2) print_status "Found PORT in .env: $PORT" # Validate PORT is numeric if [[ ! "$PORT" =~ ^[0-9]+$ ]]; then print_error "PORT is not numeric: '$PORT'. Setting to 8000." PORT="8000" sudo sed -i "s/^PORT=.*/PORT=8000/" "$ENV_FILE" fi else print_warning "PORT not found in .env, adding PORT=8000" echo "PORT=8000" | sudo tee -a "$ENV_FILE" > /dev/null fi if grep -q "^HOST=" "$ENV_FILE"; then HOST=$(grep "^HOST=" "$ENV_FILE" | cut -d'=' -f2) print_status "Found HOST in .env: $HOST" else print_warning "HOST not found in .env, adding HOST=0.0.0.0" echo "HOST=0.0.0.0" | sudo tee -a "$ENV_FILE" > /dev/null fi else print_error ".env file not found: $ENV_FILE" exit 1 fi # Step 3: Backup service file print_status "Step 3: Backing up service file" BACKUP_FILE="${SERVICE_FILE}.backup.$(date +%s)" sudo cp "$SERVICE_FILE" "$BACKUP_FILE" print_status "Backup created: $BACKUP_FILE" # Step 4: Fix service file - OPTION 1: Use shell expansion print_status "Step 4: Fixing service file ExecStart command" print_warning "Current issue: Waitress receives literal string '\$PORT' instead of expanded value" print_status "Solution 1: Use /bin/sh -c to enable shell variable expansion" # Get the virtual environment path VENV_DIR="${APP_DIR}/venv" if [[ ! -d "$VENV_DIR" ]]; then print_error "Virtual environment not found: $VENV_DIR" exit 1 fi # Read current service file to get other settings CURRENT_USER=$(grep "^User=" "$SERVICE_FILE" | cut -d'=' -f2) CURRENT_GROUP=$(grep "^Group=" "$SERVICE_FILE" | cut -d'=' -f2) CURRENT_WORKDIR=$(grep "^WorkingDirectory=" "$SERVICE_FILE" | cut -d'=' -f2) print_status "Current service settings:" print_status " User: $CURRENT_USER" print_status " Group: $CURRENT_GROUP" print_status " WorkingDirectory: $CURRENT_WORKDIR" # Create new service file with fixed ExecStart print_status "Creating fixed service file..." sudo tee "$SERVICE_FILE" > /dev/null << EOF [Unit] Description=Mock API Service After=network.target Wants=network.target [Service] Type=simple User=$CURRENT_USER Group=$CURRENT_GROUP WorkingDirectory=$CURRENT_WORKDIR Environment="PATH=$VENV_DIR/bin" Environment="PYTHONPATH=$APP_DIR" EnvironmentFile=$APP_DIR/.env # Use shell to expand environment variables ExecStart=/bin/sh -c "$VENV_DIR/bin/waitress-serve --host=\$HOST --port=\$PORT wsgi:wsgi_app" Restart=always RestartSec=10 StandardOutput=syslog StandardError=syslog SyslogIdentifier=mockapi # Security hardening NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ReadWritePaths=$APP_DIR [Install] WantedBy=multi-user.target EOF print_status "Service file updated with shell expansion." # Step 5: Alternative simpler fix - hardcode port based on .env value print_status "Alternative approach available: Hardcode port in service file" print_warning "Would you like to hardcode port $PORT in service file instead? (y/N)" read -p "Choice: " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then print_status "Hardcoding port $PORT in service file..." sudo tee "$SERVICE_FILE" > /dev/null << EOF [Unit] Description=Mock API Service After=network.target Wants=network.target [Service] Type=simple User=$CURRENT_USER Group=$CURRENT_GROUP WorkingDirectory=$CURRENT_WORKDIR Environment="PATH=$VENV_DIR/bin" Environment="PYTHONPATH=$APP_DIR" EnvironmentFile=$APP_DIR/.env # Hardcoded port based on .env value ExecStart=$VENV_DIR/bin/waitress-serve --host=$HOST --port=$PORT wsgi:wsgi_app Restart=always RestartSec=10 StandardOutput=syslog StandardError=syslog SyslogIdentifier=mockapi # Security hardening NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ReadWritePaths=$APP_DIR [Install] WantedBy=multi-user.target EOF print_status "Service file updated with hardcoded port $PORT." print_warning "Note: If you change PORT in .env, you must update service file manually." fi # Step 6: Reload and restart print_status "Step 5: Reloading systemd daemon..." sudo systemctl daemon-reload print_status "Step 6: Restarting service..." sudo systemctl restart mockapi sleep 3 # Step 7: Verify print_status "Step 7: Verifying service status..." if sudo systemctl is-active --quiet mockapi; then print_status "✓ Service is running!" echo print_status "Testing health endpoint on port $PORT..." if curl -f -s --max-time 10 http://localhost:$PORT/health > /dev/null 2>&1; then print_status "✓ Health check passed!" echo echo "=== Service Fixed Successfully ===" echo "MockAPI is now running on:" echo " URL: http://localhost:$PORT" echo " Admin: http://localhost:$PORT/admin/login" echo " Docs: http://localhost:$PORT/docs" echo " Health: http://localhost:$PORT/health" else print_warning "Health check failed (might be starting up). Checking logs..." sleep 2 if curl -f -s --max-time 5 http://localhost:$PORT/health > /dev/null 2>&1; then print_status "✓ Health check passed on second attempt!" else print_warning "Service running but health check failing. Checking logs..." sudo journalctl -u mockapi -n 20 --no-pager fi fi else print_error "Service failed to start after fix." echo print_warning "Checking service logs..." sudo journalctl -u mockapi -n 30 --no-pager echo print_warning "Trying alternative approach with simplified service file..." # Try a simpler approach - just hardcode common values print_status "Creating minimal service file..." sudo tee "$SERVICE_FILE" > /dev/null << EOF [Unit] Description=Mock API Service After=network.target [Service] Type=simple User=$CURRENT_USER Group=$CURRENT_GROUP WorkingDirectory=$APP_DIR Environment="PATH=$VENV_DIR/bin" ExecStart=$VENV_DIR/bin/waitress-serve --host=0.0.0.0 --port=8000 wsgi:wsgi_app Restart=always RestartSec=10 [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl restart mockapi sleep 3 if sudo systemctl is-active --quiet mockapi; then print_status "✓ Service started with hardcoded values!" print_warning "Running on default port 8000. Update .env to match." sudo sed -i "s/^PORT=.*/PORT=8000/" "$ENV_FILE" else print_error "All fixes failed. Please check manual configuration." sudo journalctl -u mockapi -n 30 --no-pager fi fi echo print_status "=== Fix script completed ===" echo "Backup service file: $BACKUP_FILE" echo "Current .env PORT: $PORT" echo "Current .env HOST: $HOST"