All checks were successful
HAProxy Manager Build and Push / Build-and-Push (push) Successful in 1m55s
Previously a Coraza block returned an empty 403 with only the `waf-block: request` header — a legitimate site owner caught in a false-positive had no idea what happened or how to get help. Now: - hap_header.tpl: every request gets a unique-id (uuid()) and that ID is injected back into the request as X-Request-Reference for the backend, so upstream Apache/PHP logs can correlate too. - hap_listener.tpl: on a request-phase Coraza deny we use `http-request return` with `lf-file` instead of `http-request deny`, so HAProxy renders the new errors/403-waf.html page with the request reference substituted in. The page tells the visitor a request was blocked, displays the reference, and points site owners to https://secure.anhonesthost.com/submitticket.php to open a ticket rather than exposing a public email address (avoids giving attackers a flood target). - The waf-block header and x-request-reference header are still set on the response so curl / monitoring clients can pick them up without rendering HTML. - Response-phase deny stays as the bare 403 — outbound blocks are rare in our config and an HTML body could land mid-stream. Errorfile lives at /haproxy/errors/403-waf.html (NOT under /etc/haproxy/, because that path is a named volume in deployed containers and would shadow baked-in files on existing deployments). Support workflow: visitor quotes the reference → support greps /var/log/haproxy.log for the uuid → gets timestamp + client IP + Host + URI → greps /var/log/coraza/audit.log for the matching transaction → reads the rule_id that fired. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
40 lines
2.4 KiB
Docker
40 lines
2.4 KiB
Docker
# Base image mirrored into the in-house registry to remove docker.io
|
|
# (Cloudflare R2) as a single point of failure for CI builds. The 2026-05-12
|
|
# Cloudflare incident took down docker.io blob pulls and broke this image's CI.
|
|
# Refresh procedure (run on a workstation that can reach docker.io, e.g.
|
|
# monthly or when Python patches drop):
|
|
# docker pull docker.io/library/python:3.12-slim
|
|
# docker tag docker.io/library/python:3.12-slim \
|
|
# repo.anhonesthost.net/cloud-hosting-platform/python:3.12-slim
|
|
# docker push repo.anhonesthost.net/cloud-hosting-platform/python:3.12-slim
|
|
# Future improvement: a scheduled Gitea Action that does the above automatically.
|
|
FROM repo.anhonesthost.net/cloud-hosting-platform/python:3.12-slim
|
|
RUN apt update -y && apt dist-upgrade -y && apt install socat haproxy cron certbot curl jq net-tools -y && apt clean && rm -rf /var/lib/apt/lists/*
|
|
WORKDIR /haproxy
|
|
COPY ./templates /haproxy/templates
|
|
COPY requirements.txt /haproxy/
|
|
COPY haproxy_manager.py /haproxy/
|
|
COPY scripts /haproxy/scripts
|
|
COPY trusted_ips.list /etc/haproxy/trusted_ips.list
|
|
COPY trusted_ips.map /etc/haproxy/trusted_ips.map
|
|
# /etc/haproxy is a named volume in deployed containers, so baked-in files
|
|
# under that path get shadowed by the volume on existing deployments.
|
|
# Place errorfiles outside the volumed path; the HAProxy config references
|
|
# them by absolute path.
|
|
COPY errors /haproxy/errors
|
|
RUN chmod +x /haproxy/scripts/*
|
|
RUN pip install -r requirements.txt
|
|
# Create log directories
|
|
RUN mkdir -p /var/log && touch /var/log/haproxy-manager.log /var/log/haproxy-manager-errors.log
|
|
RUN chmod 755 /var/log/haproxy-manager.log /var/log/haproxy-manager-errors.log
|
|
# Set up cron for certificate renewal with proper permissions and environment
|
|
RUN mkdir -p /var/spool/cron/crontabs && \
|
|
echo 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' > /var/spool/cron/crontabs/root && \
|
|
echo '0 */12 * * * /haproxy/scripts/renew-certificates.sh >> /var/log/haproxy-manager.log 2>&1' >> /var/spool/cron/crontabs/root && \
|
|
chmod 600 /var/spool/cron/crontabs/root && \
|
|
chown root:crontab /var/spool/cron/crontabs/root
|
|
EXPOSE 80 443 8000
|
|
# Add health check
|
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
|
CMD curl -sf --max-time 5 http://localhost:8000/health && curl -s --max-time 5 -o /dev/null http://localhost/ || exit 1
|
|
CMD ["/haproxy/scripts/start-up.sh"] |