load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so; user nginx; worker_processes auto; error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; # ── Logging ─────────────────────────────────────────────────────────────── log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" country=$geoip2_country iso=$geoip2_subdivision'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; keepalive_timeout 65; # Required when map values contain long encoded strings (status:body) map_hash_bucket_size 128; # ── GeoIP2 database ─────────────────────────────────────────────────────── # on_unavailable lets nginx start even if the .mmdb file doesn't exist yet # (e.g. first boot before geoipupdate has run). All GeoIP variables default # to their `default=` values in that case — no requests will be blocked # (fail-open). auto_reload picks up a refreshed DB from geoipupdate without # requiring an nginx restart. geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb { auto_reload 1h; $geoip2_country default=XX country iso_code; $geoip2_subdivision default="" subdivisions 0 iso_code; } # Compound key used in per-repo map blocks: "CC-SUBDIV" e.g. "US-CA" # When the DB has no subdivision the variable is empty; the key becomes "CC-" # which will not match any rule unless you explicitly add it. map "$geoip2_country-$geoip2_subdivision" $geoip2_region_key { default "$geoip2_country-$geoip2_subdivision"; include /etc/nginx/geoblock/repo_maps.conf; } # ── Per-repo block decision variables ───────────────────────────────────── # Loaded from the rendered snippet produced by geoblock_watcher. # Each repo gets a variable like $geoblock_ # with value "" (allow) or ":" (block). include /etc/nginx/geoblock/repo_vars.conf; # ── Virtual hosts ───────────────────────────────────────────────────────── include /etc/nginx/conf.d/*.conf; }