diff --git a/buildstream/_platform/linux.py b/buildstream/_platform/linux.py
index 702059a5d4b8ea08b3471ef156babf39eb5ce793..ac2488095982698cb88483418894e677e890a256 100644
--- a/buildstream/_platform/linux.py
+++ b/buildstream/_platform/linux.py
@@ -63,6 +63,10 @@ class Linux(Platform):
         self._linux32 = False
 
     def create_sandbox(self, *args, **kwargs):
+        # FIXME: we need a better way rather than hijacking
+        #        the normal setup process
+        from ..sandbox._sandboxdocker import SandboxDocker
+        return SandboxDocker(*args, **kwargs)
         if not self._local_sandbox_available:
             return self._create_dummy_sandbox(*args, **kwargs)
         else:
diff --git a/buildstream/sandbox/_sandboxdocker.py b/buildstream/sandbox/_sandboxdocker.py
new file mode 100755
index 0000000000000000000000000000000000000000..d7342a9f5ad7182eb08824782263e50b19e9124e
--- /dev/null
+++ b/buildstream/sandbox/_sandboxdocker.py
@@ -0,0 +1,87 @@
+import os
+import sys
+import stat
+import signal
+import subprocess
+from contextlib import contextmanager, ExitStack
+import psutil
+import tempfile
+
+import docker
+
+from .._exceptions import SandboxError
+from .. import utils
+from .. import _signals
+from ._mounter import Mounter
+from ._mount import MountMap
+from . import Sandbox, SandboxFlags
+
+
+DOCKERFILE = """
+FROM scratch
+
+ADD . /
+""".strip()
+
+
+class SandboxDocker(Sandbox):
+
+    def run(self, command, flags, *, cwd=None, env=None):
+        client = docker.from_env()
+        stdout, stderr = self._get_output()
+
+        # Fallback to the sandbox default settings for
+        # the cwd and env.
+        #
+        cwd = self._get_work_directory(cwd=cwd)
+        env = self._get_environment(cwd=cwd, env=env)
+
+        # Convert single-string argument to a list
+        if isinstance(command, str):
+            command = [command]
+
+        if not self._has_command(command[0], env):
+            raise SandboxError("Staged artifacts do not provide command "
+                               "'{}'".format(command[0]),
+                               reason='missing-command')
+
+        # Create the mount map, this will tell us where
+        # each mount point needs to be mounted from and to
+        mount_map = MountMap(self, flags & SandboxFlags.ROOT_READ_ONLY)
+        root_mount_source = mount_map.get_mount_source("/")
+
+        with open(os.path.join(root_mount_source, "Dockerfile"), "w") as fp:
+            fp.write(DOCKERFILE)
+
+        image, _ = client.images.build(path=root_mount_source)
+
+        volumes = {}
+
+        mount_source_overrides = self._get_mount_sources()
+        for mark in self._get_marked_directories():
+            mount_point = mark["directory"]
+            if mount_point in mount_source_overrides:
+                mount_source = mount_source_overrides[mount_point]
+            else:
+                mount_source = mount_map.get_mount_source(mount_point)
+
+            volumes[mount_source] = {"bind": mount_point}
+
+        # TODO: we need to handle root that is RO
+        # TODO: we need to handle cwd
+        # TODO: we need to handle env
+        # TODO: we need to support specific user uid/gid
+        # TODO: we need to support interactive mode
+        args = {
+            "image": image,
+            "command": command,
+            "detach": True,
+            "volumes": volumes,
+        }
+
+        container = client.containers.run(**args)
+        # TODO: we need to handle signals and react accordingly
+        status = container.wait()
+
+        self._vdir._mark_changed()
+        return status["StatusCode"]