diff --git a/CHANGELOG.md b/CHANGELOG.md
index d4447b50fc9d566e1a024a1a69be0b793b8ba950..34a28d9dadedd2c344714f5b3f3162d7f85dd9c8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,12 @@
 This file logs the changes that are actually interesting to users (new features,
 changed functionality, fixed bugs).
 
+## Version 2.0.7 (in development)
+
+- Use UPnP/SSDP to automatically find Manager when manager_url is empty.
+  This is now also the new default, since we can't provide a sane default URL anyway.
+
+
 ## Version 2.0.6 (released 2017-06-23)
 
 - Fixed incompatibility with attrs version 17.1+.
diff --git a/README.md b/README.md
index 28353875e05cc3d1799f76cf6dbc4b0735544549..83451c7def02e67cf0cead6da63ca147d5aaf153 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,8 @@ The configuration files should be in INI format, as specified by the
 All configuration keys should be placed in the `[flamenco-worker]` section of the
 config files. At least take a look at:
 
-- `manager_url`: Flamenco Manager URL.
+- `manager_url`: Flamenco Manager URL. Leave blank to auto-discover Flamenco Manager
+  on your network using UPnP/SSDP.
 - `task_types`: Space-separated list of task types this worker may execute.
 - `task_update_queue_db`: filename of the SQLite3 database holding the queue of task
   updates to be sent to the Master.
diff --git a/flamenco-worker.cfg b/flamenco-worker.cfg
index 0857b8dd6b4475af251fa32e409ce1958e052d32..ab4f60ff9255bbb46f66094dbe76f61be79df554 100644
--- a/flamenco-worker.cfg
+++ b/flamenco-worker.cfg
@@ -1,5 +1,8 @@
 [flamenco-worker]
-manager_url = http://localhost:8083/
+
+# The URL of the Flamenco Manager. Leave empty for auto-discovery via UPnP/SSDP.
+manager_url =
+
 task_types = sleep blender-render file-management
 task_update_queue_db = flamenco-worker.db
 
diff --git a/flamenco_worker/cli.py b/flamenco_worker/cli.py
index c8805d4fe7f8c2791d67baf3cfa375c325808dd8..5ab4e4871e0a2bbbed4192c8e16335189013df29 100644
--- a/flamenco_worker/cli.py
+++ b/flamenco_worker/cli.py
@@ -35,6 +35,19 @@ def main():
         confparser.erase('worker_id')
         confparser.erase('worker_secret')
 
+    # Find the Manager using UPnP/SSDP if we have no manager_url.
+    if not confparser.value('manager_url'):
+        from . import ssdp_discover
+
+        try:
+            manager_url = ssdp_discover.find_flamenco_manager()
+        except ssdp_discover.DiscoveryFailed:
+            log.fatal('Unable to find Flamenco Manager via UPnP/SSDP.')
+            raise SystemExit(1)
+
+        log.info('Found Flamenco Manager at %s', manager_url)
+        confparser.setvalue('manager_url', manager_url)
+
     # Patch AsyncIO
     from . import patch_asyncio
     patch_asyncio.patch_asyncio()
diff --git a/flamenco_worker/config.py b/flamenco_worker/config.py
index 411db829461e5d7ec6ca671fc35791be29108cfb..7ea44328875355056fc6893b23230bc6ccef6a52 100644
--- a/flamenco_worker/config.py
+++ b/flamenco_worker/config.py
@@ -14,7 +14,7 @@ CONFIG_SECTION = 'flamenco-worker'
 
 DEFAULT_CONFIG = {
     'flamenco-worker': collections.OrderedDict([
-        ('manager_url', 'http://flamenco-manager/'),
+        ('manager_url', ''),
         ('task_types', 'unknown sleep blender-render'),
         ('task_update_queue_db', 'flamenco-worker.db'),
         ('may_i_run_interval_seconds', '5'),
@@ -39,6 +39,9 @@ class ConfigParser(configparser.ConfigParser):
     def value(self, key, valtype: type=str):
         return valtype(self.get(CONFIG_SECTION, key))
 
+    def setvalue(self, key, value):
+        self.set(CONFIG_SECTION, key, value)
+
     def interval_secs(self, key) -> datetime.timedelta:
         """Returns the configuration value as timedelta."""
 
diff --git a/flamenco_worker/ssdp_discover.py b/flamenco_worker/ssdp_discover.py
new file mode 100644
index 0000000000000000000000000000000000000000..865003eaed20a961c23f8bc94a4a963bb6732d95
--- /dev/null
+++ b/flamenco_worker/ssdp_discover.py
@@ -0,0 +1,93 @@
+import logging
+import socket
+from http.client import HTTPResponse
+
+DISCOVERY_MSG = (b'M-SEARCH * HTTP/1.1\r\n' +
+                 b'ST: urn:flamenco:manager:0\r\n' +
+                 b'MX: 3\r\n' +
+                 b'MAN: "ssdp:discover"\r\n' +
+                 b'HOST: 239.255.255.250:1900\r\n\r\n')
+
+# We use site-local multicast, both in IPv6 and IPv4.
+DESTINATIONS = {
+    socket.AF_INET6: 'FF05::C',
+    socket.AF_INET: '239.255.255.250',
+}
+
+log = logging.getLogger(__name__)
+
+
+class DiscoveryFailed(Exception):
+    """Raised when we cannot find a Manager through SSDP."""
+
+
+class Response(HTTPResponse):
+    # noinspection PyMissingConstructor
+    def __init__(self, payload: bytes):
+        from io import BytesIO
+
+        self.fp = BytesIO(payload)
+        self.debuglevel = 0
+        self.strict = 0
+        self.headers = self.msg = None
+        self._method = None
+        self.begin()
+
+
+def interface_addresses():
+    for dest in ('0.0.0.0', '::'):
+        for family, _, _, _, sockaddr in socket.getaddrinfo(dest, None):
+            yield family, sockaddr[0]
+
+
+def unique(addresses):
+    seen = set()
+    for family_addr in addresses:
+        if family_addr in seen:
+            continue
+
+        seen.add(family_addr)
+        yield family_addr
+
+
+def find_flamenco_manager(timeout=1, retries=5):
+    log.info('Finding Flamenco Manager through UPnP/SSDP discovery.')
+
+    socket.setdefaulttimeout(timeout)
+    families_and_addresses = list(unique(interface_addresses()))
+
+    for _ in range(retries):
+        for family, addr in families_and_addresses:
+            try:
+                dest = DESTINATIONS[family]
+            except KeyError:
+                log.warning('Unknown address family %s, skipping', family)
+                continue
+
+            log.debug('Sending to %s %s' % (family, addr))
+
+            sock = socket.socket(family, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
+            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
+            sock.bind((addr, 0))
+
+            for _ in range(2):
+                # sending it more than once will
+                # decrease the probability of a timeout
+                sock.sendto(DISCOVERY_MSG, (dest, 1900))
+
+            try:
+                data = sock.recv(1024)
+            except socket.timeout:
+                pass
+            else:
+                response = Response(data)
+                return response.getheader('Location')
+
+    raise DiscoveryFailed('Unable to find Flamenco Manager after %i tries' % retries)
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.DEBUG)
+    location = find_flamenco_manager()
+    print('Found the service at %s' % location)