262 lines
No EOL
7.5 KiB
Bash
262 lines
No EOL
7.5 KiB
Bash
#!/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" |