#1146572 apt-cacher-ng: acng fails if HTTP 200 isn't followed by "OK"

Package:
apt-cacher-ng
Source:
apt-cacher-ng
Description:
caching proxy server for software repositories
Submitter:
Tobias Olausson
Date:
2026-09-03 10:17:02 UTC
Severity:
normal
#1146572#5
Date:
2026-09-03 10:14:16 UTC
From:
To:
Dear Maintainer,

I'm using acng in a dockerized environment as part of a CI pipeline with
debos.
The project has its own apt repo backed by jfrog artifactory. While
setting up
the caching, we found that jfrog sends "HTTP/1.1 200", and not "HTTP/1.1 200
OK", which acng seems to require, or it will hang in the request and
eventually
time out, and this seems to block the fetching from the other mirror as
well.

The apt output from the user of the cache (192.168.11.33 is my dev
machine where
the acng service is exposed, when running locally):
 > 2026/09/03 09:05:26 apt-get -y update | Hit:1
http://HTTPS///deb.debian.org/debian trixie InRelease
 > 2026/09/03 09:05:43 apt-get -y update | Ign:2
http://HTTPS///jfrog.customername.com/artifactory/reponame trixie InRelease
 > 2026/09/03 09:06:00 apt-get -y update | Ign:3
http://HTTPS///security.debian.org/debian-security trixie-security InRelease
 > 2026/09/03 09:06:17 apt-get -y update | Ign:2
http://HTTPS///jfrog.customername.com/artifactory/reponame trixie InRelease
 > 2026/09/03 09:06:34 apt-get -y update | Ign:3
http://HTTPS///security.debian.org/debian-security trixie-security InRelease
 > 2026/09/03 09:06:51 apt-get -y update | Ign:2
http://HTTPS///jfrog.customername.com/artifactory/reponame trixie InRelease
 > 2026/09/03 09:07:08 apt-get -y update | Ign:3
http://HTTPS///security.debian.org/debian-security trixie-security InRelease
 > 2026/09/03 09:07:25 apt-get -y update | Err:2
http://HTTPS///jfrog.customername.com/artifactory/reponame trixie InRelease
 > 2026/09/03 09:07:25 apt-get -y update |   500  Remote or cache error
[IP: 192.168.11.33 3142]
 > 2026/09/03 09:07:42 apt-get -y update | Err:3
http://HTTPS///security.debian.org/debian-security trixie-security InRelease
 > 2026/09/03 09:07:42 apt-get -y update |   500  Remote or cache error
[IP: 192.168.11.33 3142]
 > 2026/09/03 09:07:46 apt-get -y update | Reading package lists...
 > 2026/09/03 09:07:46 apt-get -y update | W: Failed to fetch
http://HTTPS///jfrog.customername.com/artifactory/reponame/dists/trixie/InRelease
500  Remote or cache error [IP: 192.168.11.33 3142]
 > 2026/09/03 09:07:46 apt-get -y update | W: Failed to fetch
http://HTTPS///security.debian.org/debian-security/dists/trixie-security/InRelease
500  Remote or cache error [IP: 192.168.11.33 3142]
 > 2026/09/03 09:07:46 apt-get -y update | W: Some index files failed to
download. They have been ignored, or old ones used instead.

The log output from acng (apt-cacher.err)
 > Thu Sep  3 09:05:26 2026|Decoded request URI:
http://HTTPS///jfrog.customername.com/artifactory/reponame/dists/trixie/InRelease
 > Thu Sep  3 09:05:26 2026|Processing new job,
http://HTTPS///jfrog.customername.com/artifactory/reponame/dists/trixie/InRelease
 > Thu Sep  3 09:05:43 2026|Decoded request URI:
http://HTTPS///security.debian.org/debian-security/dists/trixie-security/InRelease
 > Thu Sep  3 09:05:43 2026|Processing new job,
http://HTTPS///security.debian.org/debian-security/dists/trixie-security/InRelease
 > Thu Sep  3 09:05:59 2026|tcpconnect::ExpireCache, nextRunTime now:
9223372036854775805
 > Thu Sep  3 09:06:00 2026|Decoded request URI:
http://HTTPS///jfrog.customername.com/artifactory/reponame/dists/trixie/InRelease
 > Thu Sep  3 09:06:00 2026|Processing new job,
http://HTTPS///jfrog.customername.com/artifactory/reponame/dists/trixie/InRelease
 > Thu Sep  3 09:06:17 2026|Decoded request URI:
http://HTTPS///security.debian.org/debian-security/dists/trixie-security/InRelease
 > Thu Sep  3 09:06:17 2026|Processing new job,
http://HTTPS///security.debian.org/debian-security/dists/trixie-security/InRelease
 > Thu Sep  3 09:06:34 2026|Decoded request URI:
http://HTTPS///jfrog.customername.com/artifactory/reponame/dists/trixie/InRelease
 > Thu Sep  3 09:06:34 2026|Processing new job,
http://HTTPS///jfrog.customername.com/artifactory/reponame/dists/trixie/InRelease
 > Thu Sep  3 09:06:51 2026|Decoded request URI:
http://HTTPS///security.debian.org/debian-security/dists/trixie-security/InRelease
 > Thu Sep  3 09:06:51 2026|Processing new job,
http://HTTPS///security.debian.org/debian-security/dists/trixie-security/InRelease
 > Thu Sep  3 09:07:08 2026|Decoded request URI:
http://HTTPS///jfrog.customername.com/artifactory/reponame/dists/trixie/InRelease
 > Thu Sep  3 09:07:08 2026|Processing new job,
http://HTTPS///jfrog.customername.com/artifactory/reponame/dists/trixie/InRelease
 > Thu Sep  3 09:07:25 2026|Decoded request URI:
http://HTTPS///security.debian.org/debian-security/dists/trixie-security/InRelease
 > Thu Sep  3 09:07:25 2026|Processing new job,
http://HTTPS///security.debian.org/debian-security/dists/trixie-security/InRelease

And from apt-cacher.log
 >
1788426343|O|102|192.168.11.33|deb.debian.org/debian/dists/trixie/InRelease
 >
1788426360|O|649|192.168.11.33|jfrog.customername.com/artifactory/reponame/dists/trixie/InRelease
 >
1788426377|O|649|192.168.11.33|security.debian.org/debian-security/dists/trixie-security/InRelease
 >
1788426394|O|649|192.168.11.33|jfrog.customername.com/artifactory/reponame/dists/trixie/InRelease
 >
1788426411|O|649|192.168.11.33|security.debian.org/debian-security/dists/trixie-security/InRelease
 >
1788426428|O|649|192.168.11.33|jfrog.customername.com/artifactory/reponame/dists/trixie/InRelease
 >
1788426445|O|649|192.168.11.33|security.debian.org/debian-security/dists/trixie-security/InRelease
 >
1788426462|O|649|192.168.11.33|jfrog.customername.com/artifactory/reponame/dists/trixie/InRelease
 >
1788426462|O|649|192.168.11.33|security.debian.org/debian-security/dists/trixie-security/InRelease


However, putting an nginx proxy in front of jfrog locally with a rewrite
of the
status field fixes the issue. While I think it should be considered bad
style to
not include the OK, it's not strictly required in http.

I run the container like this to reproduce the issue. I run it with a hosts
entry added for jfrog.customername.com to get around the bug (see nginx.conf
below).
 > $ docker run -p 3142:3142 -e ACNG_MODE=populate -e ACNG_DIR=apt-cache
-v $(pwd)/apt-cache:/var/cache/apt-cacher-ng <acng-image>

Dockerfile:
 > FROM debian:trixie-slim
 >
 > RUN apt-get update && apt-get install -y --no-install-recommends \
 >     systemd \
 >     systemd-sysv \
 >     apt-cacher-ng \
 >     nginx-light \
 >     libnginx-mod-http-js \
 >     libquickjs \
 >     ca-certificates \
 >     curl \
 >     && rm -rf /var/lib/apt/lists/*
 >
 > COPY acng.conf /etc/apt-cacher-ng/acng.conf
 >
 > COPY nginx.conf /etc/nginx/nginx.conf
 > COPY fix_status.js /etc/nginx/fix_status.js
 >
 > # Create self-signed certificate for jfrog.customername.com
 > RUN mkdir /etc/nginx/ssl/ && \
 >     openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \
 >       -subj "/CN=jfrog.customername.com" \
 >       -keyout /etc/nginx/ssl/jfrog-proxy.key \
 >       -out /etc/nginx/ssl/jfrog-proxy.crt && \
 >     cp /etc/nginx/ssl/jfrog-proxy.crt
/usr/local/share/ca-certificates/jfrog-proxy.crt && \
 >     update-ca-certificates
 >
 > RUN mkdir -p /var/cache/apt-cacher-ng
 > VOLUME /var/cache/apt-cacher-ng
 >
 > # This is the port wher acng runs
 > EXPOSE 3142/tcp
 >
 > COPY entrypoint.sh /entrypoint.sh
 > RUN chmod +x /entrypoint.sh
 > ENTRYPOINT ["/entrypoint.sh"]

My entrypoint.sh looks like this.
 > #!/bin/bash
 > set -e
 >
 > CACHE_DIR="/var/cache/apt-cacher-ng"
 >
 > OFFLINE_MODE="0"
 > echo "Got ACNG_MODE from environment: ${ACNG_MODE:-}"
 > case "${ACNG_MODE:-frozen}" in
 >   frozen)   OFFLINE_MODE="1" ;;
 >   populate) OFFLINE_MODE="0" ;;
 >   *) echo "Unknown ACNG_MODE: $ACNG_MODE" >&2; exit 1 ;;
 > esac
 >
 > /usr/sbin/apt-cacher-ng -c /etc/apt-cacher-ng CacheDir="${CACHE_DIR}"
OfflineMode="${OFFLINE_MODE}" &
 > ACNG_PID=$!
 >
 > mkdir -p "${CACHE_DIR}"
 > chown -R apt-cacher-ng:apt-cacher-ng "$CACHE_DIR"
 >
 > echo "Started apt-cacher-ng (OFFLINE_MODE=${OFFLINE_MODE}), waiting
for their exit..."
 > trap 'kill $ACNG_PID 2>/dev/null' TERM INT
 > wait -n "$ACNG_PID"
 > exit $?

acng.conf:
 > # Minimalistic apt-cache-ng configuration file
 > CacheDir: /var/cache/apt-cacher-ng
 > LogDir: /var/log/apt-cacher-ng
 >
 > Port: 3142
 > BindAddress: 0.0.0.0
 >
 > VerboseLog: 1
 > Debug: 255
 >
 > ForeGround: 1
 >
 > # Set this to 1 to use the cache as a mirror only
 > Offlinemode: 0
 >
 > # Run for both HTTP and HTTPS
 > AllowUserPorts: 80 443

The nginx configuration:
 > load_module modules/ngx_http_js_module.so;
 >
 > events {}
 >
 > #
 > # This https server configuration handles one quirk that JFrog
Artifactory has
 > # in relation to using apt-cacher-ng: JFrog does not send a proper
HTTP 200 OK
 > #
 > # This server impersonates JFrog and proxies any calls to the real
one, while
 > # rewriting the responses to match what we should get. Pair this with
an entry
 > # in /etc/hosts to point jfrog.customername.com to this server.
 >
 > http {
 >     # Use an upstream resolver to avoid a loop to 127.0.0.1
 >     resolver 1.1.1.1 valid=300s;
 >     js_import fix_status.js;
 >
 >     server {
 >         listen 127.0.0.1:443 ssl;
 >         server_name jfrog.customername.com;
 >
 >         ssl_certificate     /etc/nginx/ssl/jfrog-proxy.crt;
 >         ssl_certificate_key /etc/nginx/ssl/jfrog-proxy.key;
 >
 >         location / {
 >             set $upstream https://jfrog.customername.com;
 >             proxy_pass $upstream;
 >             proxy_ssl_server_name on;
 >             proxy_set_header Host jfrog.customername.com;
 >
 >             # JFrog sends HTTP 200 (without OK), we need to rewrite
it so the
 >             # cache gets a proper response.
 >             js_header_filter fix_status.fixReason;
 >         }
 >     }
 > }

And finally the fix_status.js:
 > function fixReason(r) {
 >     r.status = r.status;   // reassign to force nginx to re-render
the status line
 > }
 >
 > export default {fixReason};

Perhaps this is a bit much, but I figured better to be verbose than to
forget
something. It should be easily reproduced by pointing to any http server
that
omits the OK. I found the difference by curl'ing the InRelease files
from debian
upstream and the jfrog server.

Response from jfrog.customername.org when curled with curl -k --http1.1 -v
 > HTTP/1.1 200
 > Date: Thu, 03 Sep 2026 09:34:35 GMT
 > Content-Type: application/octet-stream
 > Content-Length: 2718
 > ...

And from security.debian.org with the same flags:
 > HTTP/1.1 200 OK
 > Connection: keep-alive
 > Content-Length: 41759
 > ...