# Chroot can't quit

**URL:** <https://discourse.haproxy.org/t/chroot-cant-quit/12162>\
**Category:** Help!\
**Created:** [April 25, 2026, 8:03pm UTC](https://discourse.haproxy.org/t/chroot-cant-quit/12162 "2026-04-25T20:03:39Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Kodey](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.haproxy.org/kodey/32/2528_2.png) [@Kodey](https://discourse.haproxy.org/u/Kodey)\
**Post date:** [April 25, 2026, 8:03pm UTC](https://discourse.haproxy.org/t/chroot-cant-quit/12162/1 "2026-04-25T20:03:39Z")

</div>

I’m attempting to harden a forwarding proxy that currently runs on a standard Trixie deployment with haproxy version 3.0.11-1+deb13u2.  
When I try to chroot it, the control processes timeout.  
In an attempt to isolate the problem I’ve mocked a simple test system but can’t seem to get the worker process to quit with systemd or socat.  
Gemini concluded the client wasn’t listening and has advised me to change the unit file settings:

```auto
[Service]
# Pivot to simple to stop waiting for unresponsive notify signals
Type=simple

# Force immediate termination since workers are deaf inside the chroot
KillSignal=SIGKILL
TimeoutStopSec=2s

# Standard Hardening & Capabilities
RuntimeDirectory=haproxy
RuntimeDirectoryMode=0750
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_CHROOT CAP_SETGID CAP_SETUID
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_CHROOT CAP_SETGID CAP_SETUID

# Map the journal socket for visibility
BindReadOnlyPaths=/run/systemd/journal/dev-log:/var/lib/haproxy/dev/log

```

But a few socat commands to the worker proved it was healthy and responsive but didn’t terminate when sent the quit command.  
This is the mock haproxy.cfg:

```auto

global
        log /dev/log local0
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin
        stats timeout 30s
        user haproxy
        group haproxy
        master-worker

        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
        ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
        ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

defaults
        log global
        mode tcp
        timeout connect 5s
        timeout client 50s
        timeout server 50s
        option tcplog
        option dontlognull
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http

frontend tproxy_test
    bind *:8080 transparent
    default_backend local_dummy

backend local_dummy
    server loopback 127.0.0.1:9999

```

This is an ongoing test and I’m just reaching out to see if anyone here has a better solution than Gemini

---

<div class="post-metadata">

**Author:** ![lukastribus](https://avatars.discourse-cdn.com/v4/letter/l/7ea924/32.png) [@lukastribus](https://discourse.haproxy.org/u/lukastribus)\
**Post date:** [April 28, 2026, 9:21am UTC](https://discourse.haproxy.org/t/chroot-cant-quit/12162/2 "2026-04-28T09:21:02Z")

</div>

When you install haproxy on Debian Trixie, haproxy is already chrooted into `/var/lib/haproxy` and everything will just work.

```
root@debian-4gb-fsn1-1:~# grep chroot /etc/haproxy/haproxy.cfg
         chroot /var/lib/haproxy
root@debian-4gb-fsn1-1:~#

```

Nothing else is needed.
