Setting up a Django project to run as a Windows service can help ensure that your application stays online and automatically restarts after system reboots. This guide walks you through setting up Django as a Windows service using **Waitress** (a production-ready WSGI server) and **PyWin32** for managing the service. We'll also cover common problems, like making sure the service starts and stops correctly. <img src={require('./img/logo-python-django.png').default} alt="django" width="500" height="150"/> <br/> ### The Plan We'll be doing the following: 1. Set up Django to run as a Windows service using PyWin32. 2. Use Waitress to serve the Django application. 3. Handle service start/stop gracefully. 4. Troubleshoot common issues that can pop up. --- #### Step 1: Install What You Need You'll need to install Django, Waitress, and PyWin32. Run these commands to install the necessary packages: ```bash pip install django waitress pywin32 ``` After installing PyWin32, run the following command to finish the installation: ```bash python -m pywin32_postinstall ``` This step ensures the necessary Windows files for PyWin32 are in place. --- #### Step 2: Write the Python Service Script To create the Windows service, we’ll write a Python script that sets up the service and runs the Django app through Waitress. Create a file named `django_service.py` in your Django project directory (where `manage.py` is located), and paste the following code: ```python import os import sys import win32service import win32serviceutil import win32event from waitress import serve from django.core.wsgi import get_wsgi_application import logging # Set up logging for debugging logging.basicConfig( filename='C:\\path\\to\\logs\\django_service.log', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s' ) class DjangoService(win32serviceutil.ServiceFramework): _svc_name_ = "DjangoWebService" _svc_display_name_ = "Django Web Service" _svc_description_ = "A Windows service running a Django web server using Waitress." def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) self.running = True logging.info("Initializing Django service...") try: os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project_name.settings') self.application = get_wsgi_application() except Exception as e: logging.error(f"Error initializing WSGI application: {e}") def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) win32event.SetEvent(self.hWaitStop) self.running = False logging.info("Stopping Django service...") def SvcDoRun(self): logging.info("Service is running...") serve(self.application, host='0.0.0.0', port=8000) if __name__ == '__main__': win32serviceutil.HandleCommandLine(DjangoService) ``` ##### What’s Happening in the Script: - **Logging**: We set up logging to help debug issues. All logs go to `django_service.log`. - **WSGI Application**: Django’s `get_wsgi_application()` is used to initialize the app. - **Waitress**: We serve Django using Waitress, which is a good production-ready server. - **Service Methods**: - `SvcStop()`: Handles stopping the service gracefully. - `SvcDoRun()`: Runs the Waitress server. --- #### Step 3: Install the Service Once the script is ready, you need to install it as a Windows service. Run this command in the directory where your `django_service.py` is located: ```bash python django_service.py install ``` This registers your Django application as a Windows service. ##### Note: Make sure to run this command **as an administrator**. Services need elevated privileges to install properly. --- #### Step 4: Start the Service Now that the service is installed, you can start it by running: ```bash python django_service.py start ``` Alternatively, you can go to the Windows **Services** panel (`services.msc`), find "Django Web Service," and start it from there. --- #### Step 5: Troubleshooting Common Errors ##### Error 1066: Service-Specific Error This error usually happens when something crashes during the service startup. To fix it: - **Check Logs**: Look at `django_service.log` for any errors. - **Check Django Config**: Make sure that `DJANGO_SETTINGS_MODULE` is set correctly. ##### Error 1053: Service Did Not Respond in Time This happens when the service takes too long to start. You can try: - **Optimizing Django Startup**: Check if your app takes too long to start (e.g., database connections). - **Check Waitress Config**: Ensure that the server is set up properly. ##### Logs Not Generated If logs aren’t showing up: - Ensure the directory `C:\\path\\to\\logs` exists. - Make sure the service has permission to write to that directory. - Double-check that logging is set up before the service starts. --- #### Step 6: Stopping the Service Gracefully Stopping services cleanly is essential to avoid crashes or stuck processes. In the `SvcStop` method, we signal the server to stop by setting `self.running = False`. If this still doesn’t stop the service cleanly, you can add `os._exit(0)` to force an exit, but this should be a last resort. Try to allow the application to shut down properly if possible. --- #### Step 7: Configuring Allowed Hosts in Django Before you go live, ensure that the `ALLOWED_HOSTS` setting in `settings.py` is configured properly. It should include the domain or IP of your server: ```python ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'your-domain.com'] ``` This ensures Django only accepts requests from specified hosts, which is crucial for security. --- #### Step 8: Package it with PyInstaller (Optional) If you want to package everything into a single executable, you can use **PyInstaller**. Here’s how: First, install PyInstaller: ```bash pip install pyinstaller ``` Then, create the executable: ```bash pyinstaller --onefile django_service.py ``` This will create a standalone executable in the `dist` folder that you can deploy to other Windows machines. --- #### Conclusion By following this guide, you’ve successfully set up Django to run as a Windows service using **Waitress** and **PyWin32**. You’ve also learned how to: 1. Install and run the service. 2. Debug common service-related errors. 3. Ensure a clean shutdown for the service. 4. Configure Django’s `ALLOWED_HOSTS` for production. With this setup, your Django app will run efficiently as a background service, ensuring it stays available even after reboots. For more information on the topics covered in this blog, check out these resources: - [Django Documentation](https://docs.djangoproject.com/en/stable/) - [Waitress WSGI Server Documentation](https://docs.pylonsproject.org/projects/waitress/en/stable/) - [PyWin32 GitHub Repository](https://github.com/mhammond/pywin32) - [PyInstaller Documentation](https://pyinstaller.org/en/stable/) - [Python Logging Module Documentation](https://docs.python.org/3/library/logging.html)