diff --git a/docs/source/conf.py b/docs/source/conf.py
index a2d44a734..f875a8881 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -301,6 +301,7 @@ autodoc_mock_imports = [
     'bleak',
     'bluetooth_numbers',
     'TheengsDecoder',
+    'waitress',
 ]
 
 sys.path.insert(0, os.path.abspath('../..'))
diff --git a/platypush/backend/http/__init__.py b/platypush/backend/http/__init__.py
index 6e160f7be..f70c077e2 100644
--- a/platypush/backend/http/__init__.py
+++ b/platypush/backend/http/__init__.py
@@ -1,15 +1,16 @@
 import os
-import subprocess
 import threading
 
 from multiprocessing import Process
 
 try:
-    from websockets.exceptions import ConnectionClosed
+    from websockets.exceptions import ConnectionClosed  # type: ignore
     from websockets import serve as websocket_serve  # type: ignore
 except ImportError:
     from websockets import ConnectionClosed, serve as websocket_serve  # type: ignore
 
+import waitress
+
 from platypush.backend import Backend
 from platypush.backend.http.app import application
 from platypush.bus.redis import RedisBus
@@ -152,22 +153,6 @@ class HttpBackend(Backend):
         * **Session token**, generated upon login, it can be used to authenticate requests through the ``Cookie`` header
           (cookie name: ``session_token``).
 
-    Requires:
-
-        * **gunicorn** (``pip install gunicorn``) - optional, to run the Platypush webapp over uWSGI.
-
-    By default the Platypush web server will run in a
-    process spawned on the fly by the HTTP backend. However, being a
-    Flask app, it will serve clients in a single thread and it won't
-    support many features of a full-blown web server. gunicorn allows
-    you to easily spawn the web server in a uWSGI wrapper, separate
-    from the main Platypush daemon, and the uWSGI layer can be easily
-    exposed over an nginx/lighttpd web server.
-
-    Command to run the web server over a gunicorn uWSGI wrapper::
-
-        gunicorn -w <n_workers> -b <bind_address>:8008 platypush.backend.http.uwsgi
-
     """
 
     _DEFAULT_HTTP_PORT = 8008
@@ -185,8 +170,7 @@ class HttpBackend(Backend):
         ssl_cafile=None,
         ssl_capath=None,
         maps=None,
-        run_externally=False,
-        uwsgi_args=None,
+        flask_args=None,
         **kwargs,
     ):
         """
@@ -222,25 +206,8 @@ class HttpBackend(Backend):
             the value is the absolute path to expose.
         :type resource_dirs: dict[str, str]
 
-        :param run_externally: If set, then the HTTP backend will not directly
-            spawn the web server. Set this option if you plan to run the webapp
-            in a separate web server (recommended), like uwsgi or uwsgi+nginx.
-        :type run_externally: bool
-
-        :param uwsgi_args: If ``run_externally`` is set and you would like the
-            HTTP backend to directly spawn and control the uWSGI application
-            server instance, then pass the list of uWSGI arguments through
-            this parameter. Some examples include::
-
-                # Start uWSGI instance listening on HTTP port 8008 with 4
-                # processes
-                ['--plugin', 'python', '--http-socket', ':8008', '--master', '--processes', '4']
-
-                # Start uWSGI instance listening on uWSGI socket on port 3031.
-                # You can then use another full-blown web server, like nginx
-                # or Apache, to communicate with the uWSGI instance
-                ['--plugin', 'python', '--socket', '127.0.0.1:3031', '--master', '--processes', '4']
-        :type uwsgi_args: list[str]
+        :param flask_args: Extra key-value arguments that should be passed to the Flask service.
+        :type flask_args: dict[str, str]
         """
 
         super().__init__(**kwargs)
@@ -264,8 +231,7 @@ class HttpBackend(Backend):
             self.resource_dirs = {}
 
         self.active_websockets = set()
-        self.run_externally = run_externally
-        self.uwsgi_args = uwsgi_args or []
+        self.flask_args = flask_args or {}
         self.ssl_context = (
             get_ssl_server_context(
                 ssl_cert=ssl_cert,
@@ -277,13 +243,6 @@ class HttpBackend(Backend):
             else None
         )
 
-        if self.uwsgi_args:
-            self.uwsgi_args = [str(_) for _ in self.uwsgi_args] + [
-                '--module',
-                'platypush.backend.http.uwsgi',
-                '--enable-threads',
-            ]
-
         protocol = 'https' if ssl_cert else 'http'
         self.local_base_url = f'{protocol}://localhost:{self.port}'
         self._websocket_lock_timeout = 10
@@ -299,26 +258,16 @@ class HttpBackend(Backend):
         self.logger.info('Received STOP event on HttpBackend')
 
         if self.server_proc:
-            if isinstance(self.server_proc, subprocess.Popen):
+            self.server_proc.terminate()
+            self.server_proc.join(timeout=10)
+            if self.server_proc.is_alive():
                 self.server_proc.kill()
-                self.server_proc.wait(timeout=10)
-                if self.server_proc.poll() is not None:
-                    self.logger.info(
-                        'HTTP server process may be still alive at termination'
-                    )
-                else:
-                    self.logger.info('HTTP server process terminated')
+            if self.server_proc.is_alive():
+                self.logger.info(
+                    'HTTP server process may be still alive at termination'
+                )
             else:
-                self.server_proc.terminate()
-                self.server_proc.join(timeout=10)
-                if self.server_proc.is_alive():
-                    self.server_proc.kill()
-                if self.server_proc.is_alive():
-                    self.logger.info(
-                        'HTTP server process may be still alive at termination'
-                    )
-                else:
-                    self.logger.info('HTTP server process terminated')
+                self.logger.info('HTTP server process terminated')
 
         if (
             self.websocket_thread
@@ -440,8 +389,6 @@ class HttpBackend(Backend):
             kwargs = {
                 'host': self.bind_address,
                 'port': self.port,
-                'use_reloader': False,
-                'debug': False,
             }
 
             assert isinstance(
@@ -451,8 +398,10 @@ class HttpBackend(Backend):
             application.config['redis_queue'] = self.bus.redis_queue
             if self.ssl_context:
                 kwargs['ssl_context'] = self.ssl_context
+            if self.flask_args:
+                kwargs.update(self.flask_args)
 
-            application.run(**kwargs)
+            waitress.serve(application, **kwargs)
 
         return proc
 
@@ -480,20 +429,9 @@ class HttpBackend(Backend):
         self._service_registry_thread.start()
 
     def _run_web_server(self):
-        if not self.run_externally:
-            self.server_proc = Process(target=self._web_server_proc(), name='WebServer')
-            self.server_proc.start()
-            self.server_proc.join()
-        elif self.uwsgi_args:
-            uwsgi_cmd = ['uwsgi'] + self.uwsgi_args
-            self.logger.info('Starting uWSGI with arguments %s', uwsgi_cmd)
-            self.server_proc = subprocess.Popen(uwsgi_cmd)
-        else:
-            raise RuntimeError(
-                'The web server is configured to be launched externally but '
-                'no uwsgi_args were provided. Make sure that you run another external service'
-                'for the web server (e.g. nginx)'
-            )
+        self.server_proc = Process(target=self._web_server_proc(), name='WebServer')
+        self.server_proc.start()
+        self.server_proc.join()
 
     def run(self):
         super().run()
diff --git a/platypush/backend/http/uwsgi.py b/platypush/backend/http/uwsgi.py
deleted file mode 100644
index 6312c2e92..000000000
--- a/platypush/backend/http/uwsgi.py
+++ /dev/null
@@ -1,11 +0,0 @@
-"""
-uWSGI webapp entry point
-"""
-
-from platypush.backend.http.app import application
-
-if __name__ == '__main__':
-    application.run()
-
-
-# vim:sw=4:ts=4:et:
diff --git a/requirements.txt b/requirements.txt
index e67185939..b00880996 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -22,3 +22,4 @@ paho-mqtt
 websocket-client
 croniter
 python-magic
+waitress
diff --git a/setup.py b/setup.py
index 85dc5187e..f79522547 100755
--- a/setup.py
+++ b/setup.py
@@ -60,25 +60,26 @@ setup(
         "Development Status :: 4 - Beta",
     ],
     install_requires=[
+        'alembic',
+        'bcrypt',
+        'croniter',
+        'flask',
+        'frozendict',
+        'marshmallow',
+        'marshmallow_dataclass',
+        'python-dateutil',
+        'python-magic',
         'pyyaml',
         'redis',
         'requests',
-        'croniter',
+        'rsa',
         'sqlalchemy',
-        'alembic',
-        'websockets',
+        'tz',
+        'waitress',
         'websocket-client',
+        'websockets',
         'wheel',
         'zeroconf>=0.27.0',
-        'tz',
-        'python-dateutil',
-        'rsa',
-        'marshmallow',
-        'marshmallow_dataclass',
-        'frozendict',
-        'flask',
-        'bcrypt',
-        'python-magic',
     ],
     extras_require={
         # Support for thread custom name
@@ -89,8 +90,9 @@ setup(
         'pushbullet': [
             'pushbullet.py @ https://github.com/rbrcsk/pushbullet.py/tarball/master'
         ],
-        # Support for HTTP backend over uWSGI
-        'http': ['gunicorn'],
+        # This is only kept for back-compatibility purposes, as all the
+        # dependencies of the HTTP webserver are now core dependencies.
+        'http': [],
         # Support for MQTT backends
         'mqtt': ['paho-mqtt'],
         # Support for RSS feeds parser
@@ -230,7 +232,7 @@ setup(
         # Support for zigbee2mqtt
         'zigbee': ['paho-mqtt'],
         # Support for Z-Wave
-        'zwave': ['python-openzwave'],
+        'zwave': ['paho-mqtt'],
         # Support for Mozilla DeepSpeech speech-to-text engine
         'deepspeech': ['deepspeech', 'numpy', 'sounddevice'],
         # Support for PicoVoice hotword detection engine