diff --git a/worker/src/main.rs b/worker/src/main.rs
index 3a08164a099ac85676cb011c54ff306edd7dbac1..41085eb1c60f4bd3f8796a3f1ef75af7165373fb 100644
--- a/worker/src/main.rs
+++ b/worker/src/main.rs
@@ -187,7 +187,7 @@ async fn main() -> Result<()> {
                 }],
                 input_url: build.input_url,
                 backend,
-                build: config::Build::default(),
+                build: config.build,
                 diffoscope,
                 privkey: &profile.privkey,
             }).await?;
diff --git a/worker/src/proc.rs b/worker/src/proc.rs
index 0ecb6fd2de0ccfbd31417f10eefd8dc1c6369dcb..a2845a593a40b26a4fcee9601e0b4e56024ac8b5 100644
--- a/worker/src/proc.rs
+++ b/worker/src/proc.rs
@@ -73,11 +73,18 @@ impl Capture {
         Ok(())
     }
 
+    fn kill(pid: u32, signal: Signal) -> Result<()> {
+        // convert 1234 to -1234 to kill grand-children too
+        let pid = -(pid as i32);
+        info!("Sending {} to child(pid={})", signal, pid);
+        signal::kill(Pid::from_raw(pid), signal)?;
+        Ok(())
+    }
+
     async fn truncate(&mut self, child: &mut Child, reason: &str, kill: bool) -> Result<()> {
         if kill {
             if let Some(pid) = child.id() {
-                info!("Sending SIGTERM to child(pid={})", pid);
-                signal::kill(Pid::from_raw(pid as i32), Signal::SIGTERM)?;
+                Self::kill(pid, Signal::SIGTERM)?;
             }
             self.sigterm_sent = Some(Instant::now());
         }
@@ -87,14 +94,16 @@ impl Capture {
         Ok(())
     }
 
-    pub async fn next_wakeup(&mut self, child: &mut Child) -> Result<Duration> {
+    pub async fn next_wakeup(&mut self, child: &mut Child, stdout_open: &mut bool, stderr_open: &mut bool) -> Result<Duration> {
         // check if we need to SIGKILL due to SIGTERM timeout
         if let Some(sigterm_sent) = self.sigterm_sent {
             if sigterm_sent.elapsed() > Duration::from_secs(SIGKILL_DELAY) {
                 if let Some(pid) = child.id() {
                     warn!("child(pid={}) didn't terminate {}s after SIGTERM, sending SIGKILL", pid, SIGKILL_DELAY);
                     // child.id is going to return None after this
-                    child.kill().await?;
+                    Self::kill(pid, Signal::SIGKILL)?;
+                    *stdout_open = false;
+                    *stderr_open = false;
                 }
             }
         }
@@ -118,13 +127,26 @@ pub async fn run<I, S>(bin: &Path, args: I, opts: Options) -> Result<(bool, Stri
     S: AsRef<OsStr>,
 {
     info!("Running {:?} {:?}", bin, args);
-    let mut child = Command::new(bin)
+    let mut cmd = Command::new(bin);
+    cmd
         .args(args)
         .stdin(Stdio::null())
         .stdout(Stdio::piped())
         .stderr(Stdio::piped())
-        .envs(&opts.envs)
-        .spawn()?;
+        .envs(&opts.envs);
+
+    unsafe {
+        cmd.pre_exec(|| {
+            // create a new process group
+            let pid = nix::unistd::getpid();
+            if let Err(err) = nix::unistd::setpgid(pid, Pid::from_raw(0)) {
+                warn!("Failed to create new process group: {:#?}", err);
+            }
+            Ok(())
+        });
+    }
+
+    let mut child = cmd.spawn()?;
 
     let mut child_stdout = child.stdout.take().unwrap();
     let mut child_stderr = child.stderr.take().unwrap();
@@ -140,12 +162,13 @@ pub async fn run<I, S>(bin: &Path, args: I, opts: Options) -> Result<(bool, Stri
     let mut stderr_open = true;
     let mut cap = capture(opts);
     let (success, output) = loop {
-        let remaining = cap.next_wakeup(&mut child).await?;
+        let remaining = cap.next_wakeup(&mut child, &mut stdout_open, &mut stderr_open).await?;
 
         if stdout_open || stderr_open {
             select! {
                 n = child_stdout.read(&mut buf_stdout).fuse() => {
                     let n = n?;
+                    trace!("read stdout: {}", n);
                     if n == 0 {
                         stdout_open = false;
                     } else {
@@ -157,6 +180,7 @@ pub async fn run<I, S>(bin: &Path, args: I, opts: Options) -> Result<(bool, Stri
                 },
                 n = child_stderr.read(&mut buf_stderr).fuse() => {
                     let n = n?;
+                    trace!("read stderr: {}", n);
                     if n == 0 {
                         stderr_open = false;
                     } else {