GoAccess using Docker behind a Traefik proxy
Closed this issue · 2 comments
Hello, I'm trying to set up goaccess in Docker behind a traefik proxy. The example in the goaccess repo is helpful, but doesn't get me working and it doesn't explain its changes, e.g. why is it using port 443?
I've attached a screenshot from my browser.
I should also note that I get what looks like a good connection via curl
$ curl -v -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" https://goaccess.MYDOMAIN.TLD
... bunch of protocol stuff ...
accept-ranges: bytes
content-type: text/html
date: Sun, 01 Jun 2025 17:00:18 GMT
etag: "683c8511-b5414"
last-modified: Sun, 01 Jun 2025 16:51:29 GMT
permissions-policy: interest-cohort=()
server: nginx/1.27.5
strict-transport-security: max-age=31536000; includeSubDomains; preload
content-length: 742420
<!DOCTYPE html><html lang='en'><head><meta charset='UTF-8'>
...
r.sphericalTriangleArea=function(r){return 2*nr(w(r,!1))},Object.defineProperty(r,"__esModule",{value:!0})});</script></body></html>
However, websocat shows problems:
$ ./websocat.x86_64-unknown-linux-musl -t --log-verbose wss://goaccess.MYDOMAIN.TLD
2025-06-01T17:11:32.871822Z ERROR websocat::scenario_executor::utils1: Upstream server returned status code other than `switching protocols`: 200 OK
I have about six files of configuration. Three for treafik (base/static/dynamic), one for goaccess compose, one nginx, and one goaccess.conf.
I haven't made changes to the nginx.conf compared to the one in the goaccess repo.
goaccess/docker-compose.yml
services:
goaccess-nginx:
image: nginx:alpine
container_name: goaccess-nginx
restart: unless-stopped
security_opt:
- no-new-privileges:true
volumes:
- /srv/goaccess/config/nginx.conf:/etc/nginx/nginx.conf:ro
- goaccess-data:/usr/share/nginx/html:ro
networks:
- proxy
depends_on:
- goaccess
labels:
- "traefik.enable=true"
# main HTTP service (NGINX serving static files)
- "traefik.http.routers.goaccess-nginx.rule=Host(`goaccess.${DOMAINNAME}`)"
- "traefik.http.routers.goaccess-nginx.entrypoints=websecure"
- "traefik.http.routers.goaccess-nginx.tls=true"
- "traefik.http.routers.goaccess-nginx.tls.certresolver=le-cf"
- "traefik.http.services.goaccess-nginx.loadbalancer.server.port=80"
goaccess:
image: allinurl/goaccess:latest
container_name: goaccess
restart: unless-stopped
security_opt:
- no-new-privileges:true
volumes:
- /srv/goaccess/config/goaccess.conf:/srv/config/goaccess.conf:ro
- /mnt/httpd/logs/access.log:/srv/logs/access.log:ro
- goaccess-data:/srv/report/
command: ["--no-global-config", "--config-file=/srv/config/goaccess.conf"]
labels:
- "traefik.enable=true"
- "traefik.http.services.goaccess.loadbalancer.server.port=443"
- "traefik.http.middlewares.websocket-headers.headers.customrequestheaders.Connection=Upgrade"
- "traefik.http.middlewares.websocket-headers.headers.customrequestheaders.Upgrade=websocket"
- "traefik.http.middlewares.websocket-headers.headers.customrequestheaders.Host=goaccess.${DOMAINNAME}"
- "traefik.http.routers.websocket.middlewares=websocket-headers"
networks:
- proxy
volumes:
goaccess-data:
I realise they customrequestheaders are probably not needed, but I was grasping at straws :)
config/goaccess.conf
tz America/Vancouver
time-format %H:%M:%S
date-format %Y-%m-%d
log-format COMBINED
log-file /srv/logs/access.log
output /srv/report/index.html
real-time-html true
ws-url wss://goaccess.MYDOMAIN.TLD
port 443
traefik/docker-compose.yml
secrets:
zde_token:
file: "./secrets/zde_MYDOMAIN.TLD.token"
zzr_token:
file: "./secrets/zzr_MYDOMAIN.TLD.token"
services:
traefik:
image: "traefik:latest"
container_name: "traefik"
restart: unless-stopped
security_opt:
- no-new-privileges:true
secrets:
- "zzr_token"
- "zde_token"
ports:
- 80:80
- 443:443
environment:
- CF_ZONE_API_TOKEN_FILE=/run/secrets/zzr_token
- CF_DNS_API_TOKEN_FILE=/run/secrets/zde_token
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ${TRAEFIK_HOME}/data/acme-lecf.json:/acme-lecf.json:rw
- ${TRAEFIK_HOME}/data/logs:/logs:rw
- ./dynamic.yml:/dynamic.yml:ro
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.traefik-secure.entrypoints=websecure"
- "traefik.http.routers.traefik-secure.rule=Host(`traefik.${DOMAINNAME}`)"
- "traefik.http.routers.traefik-secure.service=api@internal"
- "traefik.http.routers.traefik-secure.middlewares=ip-whitelist@file"
traefik/traefik.yml
global:
checkNewVersion: true
sendAnonymousUsage: false
api:
dashboard: true
entryPoints:
ssh:
address: :22
web:
address: :80
forwardedHeaders:
trustedIPs:
- "127.0.0.1/32"
- "192.168.0.0/16"
- "172.16.0.0/12"
- "10.0.0.0/8"
http:
redirections:
entrypoint:
to: websecure
websecure:
address: :443
forwardedHeaders:
trustedIPs:
- "127.0.0.1/32"
- "192.168.0.0/16"
- "172.16.0.0/12"
- "10.0.0.0/8"
transport:
respondingTimeouts:
readTimeout: 300s # Time to read entire request (default: 60s)
writeTimeout: 300s # Time to write response (default: 60s)
idleTimeout: 300s # Time between requests (default: 180s)
http:
middlewares:
- secureHeaders@file
- nofloc@file
tls:
certResolver: le-cf
domains:
- main: MYDOMAIN.TLD
sans:
- "*.MYDOMAIN.TLD"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
file:
filename: /dynamic.yml
certificatesResolvers:
le-cf:
acme:
email: "USER@EXAMPLE.ORG"
storage: acme-lecf.json
keyType: EC384
dnsChallenge:
provider: cloudflare
delayBeforeCheck: 60
log:
level: DEBUG
and finally, the dynamic:
traefik/dynamic.yml
http:
middlewares:
ip-whitelist:
ipAllowList:
sourcerange:
- 127.0.0.1/32
- 192.168.0.0/16
nofloc:
headers:
customResponseHeaders:
Permissions-Policy: "interest-cohort=()"
secureHeaders:
headers:
sslRedirect: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
gitea-buffer:
buffering:
maxRequestBodyBytes: 1073741824 # 1GB for large uploads
memRequestBodyBytes: 52428800 # 50MB in memory
maxResponseBodyBytes: 1073741824 # 1GB for large downloads
memResponseBodyBytes: 52428800 # 50MB in memory
retryExpression: "IsNetworkError() && Attempts() <= 2"
tls:
options:
default:
cipherSuites:
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
minVersion: VersionTLS12
Any help getting this sorted will be appreciated.
Thank you,
Tomasz
Okay, I figured it out. I was missing priorities and upgrade header in the Host router. Here's my fixed docker-compose.yml:
services:
goaccess-nginx:
image: nginx:alpine
container_name: goaccess-nginx
restart: unless-stopped
security_opt:
- no-new-privileges:true
volumes:
- /srv/goaccess/config/nginx.conf:/etc/nginx/nginx.conf:ro
- /srv/goaccess/public:/usr/share/nginx/html:ro
depends_on:
- goaccess
labels:
- "traefik.enable=true"
# main HTTP service (NGINX serving static files)
- "traefik.http.routers.goaccess-nginx.entrypoints=websecure"
- "traefik.http.routers.goaccess-nginx.rule=Host(`goaccess.${DOMAINNAME}`)"
- "traefik.http.routers.goaccess-nginx.tls=true"
- "traefik.http.routers.goaccess-nginx.tls.certresolver=le-cf"
- "traefik.http.services.goaccess-nginx.loadbalancer.server.port=80"
- "traefik.http.routers.goaccess-nginx.priority=1"
# Security and access control middlewares
- "traefik.http.routers.goaccess-secure.middlewares=ip-whitelist@file"
networks:
- proxy
goaccess:
image: allinurl/goaccess:latest
container_name: goaccess
restart: unless-stopped
security_opt:
- no-new-privileges:true
volumes:
- /srv/goaccess/config/goaccess.conf:/srv/config/goaccess.conf:ro
- /mnt/httpd/logs/access.log:/srv/logs/access.log:ro
- /srv/goaccess/public:/srv/report
command: [
"--no-global-config",
"--config-file=/srv/config/goaccess.conf"
]
labels:
- "traefik.enable=true"
- "traefik.http.routers.goaccess.rule=Host(`goaccess.${DOMAINNAME}`) && Header(`Connection`, `Upgrade`)"
- "traefik.http.routers.goaccess.entrypoints=websecure"
- "traefik.http.routers.goaccess.tls=true"
- "traefik.http.services.goaccess.loadbalancer.server.port=443"
- "traefik.http.routers.goaccess.tls.certresolver=le-cf"
- "traefik.http.routers.goaccess.priority=10"
# Security and access control middlewares
- "traefik.http.routers.goaccess-secure.middlewares=ip-whitelist@file"
networks:
- proxy
Thanks for sharing those findings!
