wsgi error: Address already in use - socketio/django/apache2

ghz 昨天 ⋅ 3 views

My project is created with React (create-react-app), React router (no webpack), -- Django (rest) and Socketio with eventlet on the backend. I have 3 problems with deployment with apache2 - Everything worked perfectly on development:

Created 2 conf files, one for the frontend port 80 and one for the backend port 8000 - separetely they work fine relatively.

The problem I have with deployment:

  • Socket.io gives
[wsgi:error] 
eventlet.wsgi.server(eventlet.listen(("", 8000)), application, log_output=False)
sock.bind(addr)
Address already in use
  • checked what uses the port --> only apache2 and it gives the same result with any other port
  • tried to create a separate conf file for socket with port 5000 (changing the port in wsgi eventlet line), same result the socketFile.conf:
Listen 5000
<VirtualHost *:5000>
    ServerName www.example.com
    ServerAlias example.com
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

<Directory /home/path/to/main/folder>
    <Files wsgi.py>
        Require all granted
    </Files>
</Directory>
WSGIDaemonProcess exampleSocket python-home=/home/path/to/venv python-path=/home/path/to/main/folder
WSGIProcessGroup exampleSocket
WSGIScriptAlias / /path/to/wsgi.py
</VirtualHost>
  • the next line is done by default with eventlet (reuse_addr=True, reuse_port=None) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

socketio_app/views.py

async_mode = None

import os
import socketio

basedir = os.path.dirname(os.path.realpath(__file__))
sio = socketio.Server(
    async_mode=async_mode, 
    logger=False, 
    cors_allowed_origins='http://localhost:3000'
)
thread = None
...

wsgi.py

import os
from django.core.wsgi import get_wsgi_application
from socketio_app.views import sio
import socketio
import eventlet
import eventlet.wsgi

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "server.settings")

application = get_wsgi_application()

application = socketio.WSGIApp(sio, application)

eventlet.wsgi.server(eventlet.listen(("", 8000)), application, log_output=False)

Answer

It seems that the error Address already in use is happening because the port you're trying to bind to (in this case, port 8000 or 5000) is already in use, possibly by another service like Apache2, or your app is trying to bind twice to the same port.

Here are some steps to troubleshoot and resolve this:

1. Check Port Usage

Make sure no other services are using the port. Run this command to check what process is using the port:

sudo lsof -i :8000

If the port is in use by another process (e.g., Apache2 or an already running instance of your app), kill the process:

sudo kill -9 <PID>

You can also check for port 5000 or whatever other port you are using.

2. Configure Eventlet Correctly

Eventlet is designed to handle concurrent connections asynchronously, but it seems you might have a configuration issue with Apache2 or the way it's being invoked with WSGI.

In wsgi.py, you're calling eventlet.wsgi.server() after wrapping the application with socketio.WSGIApp. However, you should avoid starting the Eventlet server in your WSGI file when using Apache2 with mod_wsgi.

Try removing the line:

eventlet.wsgi.server(eventlet.listen(("", 8000)), application, log_output=False)

Apache should be handling the process of running the WSGI application, so there's no need to manually start an eventlet server. The WSGI application should be run as a service by Apache.

3. Separate Apache Configurations

Ensure your socketFile.conf (for Socket.io on port 5000) is not conflicting with other Apache configurations. Double-check your Apache config files and ensure that the socket file is being properly handled and isolated.

Here’s a refined example of your configuration for Socket.io:

socketFile.conf (Apache config for port 5000):

Listen 5000
<VirtualHost *:5000>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /path/to/your/socketapp

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    <Directory /path/to/your/socketapp>
        <Files wsgi.py>
            Require all granted
        </Files>
    </Directory>

    WSGIDaemonProcess socketApp python-home=/home/path/to/venv python-path=/path/to/socketapp
    WSGIProcessGroup socketApp
    WSGIScriptAlias / /path/to/socketapp/wsgi.py
</VirtualHost>

4. Use mod_proxy and mod_proxy_uwsgi (If Apache2 is fronting)

If you continue to run into issues with eventlet trying to bind to ports that are managed by Apache, consider using Apache’s mod_proxy to forward requests to your Socket.io server. For example:

<VirtualHost *:80>
    ServerName www.example.com
    ProxyPass /socket.io/ http://127.0.0.1:5000/socket.io/
    ProxyPassReverse /socket.io/ http://127.0.0.1:5000/socket.io/

    # Other Apache configuration for frontend, etc.
</VirtualHost>

This would allow Apache to forward Socket.io traffic to a local eventlet server running on port 5000.

5. Check if async_mode is set correctly

While you're initializing socketio.Server(), make sure async_mode is set correctly. For eventlet, it's typically better to leave it as None because eventlet works by default with the gevent async model.

sio = socketio.Server(async_mode='eventlet', logger=True, cors_allowed_origins='http://localhost:3000')

Let me know if these steps help or if you're still facing issues!