diff --git a/Dockerfile b/Dockerfile index c9347b5..2cc0ed5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,24 +17,28 @@ ARG TARGETPLATFORM # chromium for rendering; ca-certificates for HTTPS; tzdata for sane timestamps; # the font package so rendered pages have glyphs to lay out. RUN apk add --no-cache chromium ca-certificates tzdata font-noto \ - && adduser -D -H -u 10001 kage \ - && mkdir -p /out \ - && chown kage:kage /out + && mkdir -p /out COPY $TARGETPLATFORM/kage /usr/bin/kage -USER kage WORKDIR /out # Point kage at the bundled Chromium and write mirrors under /out by default: # # docker run -v "$PWD/out:/out" ghcr.io/tamnd/kage clone example.com # -# The kage user has no home directory of its own, so HOME points at the mounted -# /out volume. That keeps two things writable: kage's default output and resume -# state (it lands under $HOME/data/kage), and Chrome's profile and crash -# database. Without this both fail with a permission error in the container -# (issue #7), and the mounted volume captures nothing. +# The container runs as root, and that is deliberate (issue #7). A bind-mounted +# /out is owned by whoever created it on the host, so only root can reliably +# write into it; a fixed non-root uid cannot, and both kage's output and resume +# state (under $HOME/data/kage) then fail with "mkdir /out: permission denied". +# The same unwritable HOME also breaks Chrome: it launches chrome_crashpad_handler +# with an empty crash database path, which aborts the whole browser with +# "chrome_crashpad_handler: --database is required" and fails every render. +# Running as root keeps /out and HOME writable whatever the host owns, so the +# one-liner above just works. This costs nothing in the sandbox: Chrome's sandbox +# is already off inside any container (kage drops it on container detection), so +# root here does not loosen a boundary that was holding. HOME points at /out so +# the default output and Chrome's writable state both land in the mounted volume. ENV KAGE_CHROME=/usr/bin/chromium-browser \ HOME=/out diff --git a/browser/pool.go b/browser/pool.go index 675d00c..6184a71 100644 --- a/browser/pool.go +++ b/browser/pool.go @@ -183,13 +183,14 @@ func (p *Pool) getBrowser() (*rod.Browser, error) { // In a container, the default /dev/shm is only 64 MB, too small for // Chrome's renderer on large pages, so steer it to a temp file instead. // Outside a container /dev/shm is roomy and faster, so leave it alone. - // Chrome's crashpad handler also aborts with "--database is required" in a - // minimal container, which fails the whole launch (issue #7), so turn the - // crash reporter off there. kage never uploads Chrome crash dumps anyway. + // + // The "chrome_crashpad_handler: --database is required" abort seen in + // containers (issue #7) is not fixed here: the crash-reporter flags do not + // stop Chrome from spawning the handler. Its real cause is an unwritable + // HOME, which leaves the crash database path empty; the image keeps HOME + // writable instead (see the Dockerfile). if inContainer() { - l = l.Set("disable-dev-shm-usage", ""). - Set("disable-crash-reporter", ""). - Set("disable-breakpad", "") + l = l.Set("disable-dev-shm-usage", "") } if bin := p.chromeBin(); bin != "" {