diff --git a/deploy/varnish/default.vcl.template b/deploy/varnish/default.vcl.template new file mode 100644 index 0000000..261bec7 --- /dev/null +++ b/deploy/varnish/default.vcl.template @@ -0,0 +1,88 @@ +vcl 4.1; + +import vsthrottle; +import std; + +backend app { + .host = "app"; + .port = "${APP_PORT}"; +} + +acl purge { "127.0.0.1"; "::1"; } + +sub vcl_recv { + # RATE LIMIT: 100 żądań / 10s, blokada 60s + if (vsthrottle.is_denied(client.identity, 100, 10s, 60s)) { + return (synth(429, "Too Many Requests")); + } + + # PURGE tylko lokalnie + if (req.method == "PURGE") { + if (!client.ip ~ purge) { return (synth(405, "Not allowed")); } + return (purge); + } + + # omijamy cache dla healthchecków / wewnętrznych nagłówków + if (req.url == "/healthcheck" || req.http.X-Internal-Check) { return (pass); } + + # Specjalna obsługa WebSocket i socket.io + if (req.http.Upgrade ~ "(?i)websocket" || req.url ~ "^/socket.io/") { + return (pipe); + } + + # metody inne niż GET/HEAD bez cache + if (req.method != "GET" && req.method != "HEAD") { return (pass); } + + # statyczne – agresywny cache + if (req.url ~ "^/static/" || req.url ~ "\.(css|js|png|jpg|svg|ico|woff2?)$") { + return (hash); + } + + return (hash); +} + +sub vcl_pipe { + if (req.http.Upgrade) { + set bereq.http.Upgrade = req.http.Upgrade; + set bereq.http.Connection = req.http.Connection; + } +} + +sub vcl_backend_response { + if (beresp.http.Cache-Control ~ "(?i)no-store|private") { + set beresp.uncacheable = true; + set beresp.ttl = 0s; + return (deliver); + } + + if (beresp.http.Cache-Control ~ "(?i)s-maxage=([0-9]+)") { + set beresp.ttl = std.duration(regsub(beresp.http.Cache-Control, "(?i).*s-maxage=([0-9]+).*", "\1") + "s", 0s); + } else if (beresp.http.Cache-Control ~ "(?i)max-age=([0-9]+)") { + set beresp.ttl = std.duration(regsub(beresp.http.Cache-Control, "(?i).*max-age=([0-9]+).*", "\1") + "s", 0s); + } else if (beresp.http.Expires) { + set beresp.ttl = std.time(beresp.http.Expires, now) - now; + if (beresp.ttl < 0s) { set beresp.ttl = 0s; } + } else { + set beresp.ttl = 60s; + } + + if (beresp.http.Cache-Control ~ "(?i)immutable") { + set beresp.grace = 1h; + set beresp.keep = 24h; + } + + if ((bereq.url ~ "^/static/" || bereq.url ~ "\.(css|js|png|jpg|svg|ico|woff2?)$") + && !(beresp.http.Cache-Control ~ "(?i)(s-maxage|max-age)")) { + set beresp.ttl = 24h; + } +} + +sub vcl_deliver { + if (obj.hits > 0) { + set resp.http.X-Cache = "HIT"; + } + + unset resp.http.Via; + unset resp.http.X-Varnish; + unset resp.http.Server; +} diff --git a/deploy_docker.sh b/deploy_docker.sh index 0f33aaf..2e53b07 100644 --- a/deploy_docker.sh +++ b/deploy_docker.sh @@ -1,6 +1,15 @@ #!/bin/bash set -e +# --- Wczytaj zmienne z .env --- +if [[ -f .env ]]; then + set -a + source .env + set +a +fi + +APP_PORT="${APP_PORT:-8080}" + PROFILE=$1 if [[ -z "$PROFILE" ]]; then @@ -18,6 +27,9 @@ fi echo "Pobieram najnowszy kod z repozytorium..." git pull +echo "Generowanie default.vcl z APP_PORT=$APP_PORT" +envsubst < deploy/varnish/default.vcl.template > deploy/varnish/default.vcl + echo "Zapisuję hash commita do version.txt..." git rev-parse --short HEAD > version.txt diff --git a/docker-compose.yml b/docker-compose.yml index cfc632d..d0d66fa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,13 @@ services: app: build: . - container_name: live-lista-zakupow - ports: - - "${APP_PORT:-8000}:8000" + container_name: lista-zakupow-app + #ports: + # - "${APP_PORT:-8000}:8000" + expose: + - "${APP_PORT}" healthcheck: - test: ["CMD", "python", "-c", "import urllib.request; import sys; req = urllib.request.Request('http://localhost:8000/healthcheck', headers={'X-Internal-Check': '${HEALTHCHECK_TOKEN}'}); sys.exit(0) if urllib.request.urlopen(req).read() == b'OK' else sys.exit(1)"] + test: ["CMD", "python", "-c", "import urllib.request; import sys; req = urllib.request.Request('http://localhost:${APP_PORT}/healthcheck', headers={'X-Internal-Check': '${HEALTHCHECK_TOKEN}'}); sys.exit(0) if urllib.request.urlopen(req).read() == b'OK' else sys.exit(1)"] interval: 30s timeout: 10s retries: 3 @@ -18,6 +20,27 @@ services: - ./instance:/app/instance restart: unless-stopped + varnish: + image: varnish:latest + container_name: lista-zakupow-varnish + depends_on: + app: + condition: service_healthy + ports: + - "${APP_PORT:-8080}:80" + volumes: + - ./deploy/varnish/default.vcl:/etc/varnish/default.vcl:ro + environment: + - VARNISH_SIZE=256m + healthcheck: + test: [ "CMD-SHELL", "curl -fsS -H 'X-Internal-Check=${HEALTHCHECK_TOKEN}' http://localhost/healthcheck | grep -q OK" ] + interval: 30s + timeout: 5s + retries: 3 + env_file: + - .env + restart: unless-stopped + pgsql: image: postgres:17 container_name: pgsql-db