# Systemd service for the FastAPI web application (Gunicorn + Uvicorn workers). # # Install: sudo cp this file to /etc/systemd/system/crop-ai-api.service # then: # sudo systemctl daemon-reload # sudo systemctl enable crop-ai-api # sudo systemctl start crop-ai-api # sudo systemctl status crop-ai-api # # Logs: journalctl -u crop-ai-api -f # # Replace /opt/crop-ai-system with the actual deployment path on the VPS, # and `cropai` with the dedicated non-root system user this service # should run as (create with: sudo useradd -r -s /bin/false cropai). [Unit] Description=AI Crop Decision Support System - FastAPI web application After=network.target postgresql.service redis-server.service Wants=postgresql.service redis-server.service [Service] Type=notify User=cropai Group=cropai WorkingDirectory=/opt/crop-ai-system EnvironmentFile=/opt/crop-ai-system/.env # 4 worker processes is a reasonable starting point for a modest VPS # (2-4 CPU cores). Tune with: workers = (2 x CPU cores) + 1, but cap it # based on available RAM — each worker holds its own Python process # memory, though note the heavy ML models live in Celery workers, not # here, so these web workers stay relatively light. ExecStart=/opt/crop-ai-system/venv/bin/gunicorn app.main:app \ --workers 4 \ --worker-class uvicorn.workers.UvicornWorker \ --bind 127.0.0.1:8000 \ --timeout 30 \ --graceful-timeout 30 \ --keep-alive 5 \ --access-logfile /opt/crop-ai-system/logs/gunicorn-access.log \ --error-logfile /opt/crop-ai-system/logs/gunicorn-error.log \ --log-level info ExecReload=/bin/kill -s HUP $MAINPID Restart=on-failure RestartSec=5 # Hardening NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ReadWritePaths=/opt/crop-ai-system/logs [Install] WantedBy=multi-user.target