Skip to content

Nginx in Docker with GeoIP

To use the GeoIP2 module. We pretty much need to use a Dockerfile to start with the latest nginx, but then compile the GeoIP2 module from source. This is preferred because using precompiled binaries is actually challenging - we have to ensure we get the binary that was compiled with the same nginx version that we have. Compiling the module ourselves actually simplifies this process.

FROM nginx:latest

# Install dependencies
RUN apt-get update && apt-get install -y \
    wget \
    git \
    curl \
    unzip \
    libmaxminddb-dev \
    build-essential \
    libpcre3 \
    libpcre3-dev \
    zlib1g-dev \
    libssl-dev

# Download Nginx source matching installed version
RUN nginx_version=$(nginx -v 2>&1 | awk -F/ '{print $2}') && \
    wget http://nginx.org/download/nginx-${nginx_version}.tar.gz && \
    tar -xzvf nginx-${nginx_version}.tar.gz && \
    cd nginx-${nginx_version} && \
    git clone https://github.com/leev/ngx_http_geoip2_module.git

# Configure, compile, and install the module
RUN cd nginx-$(nginx -v 2>&1 | awk -F/ '{print $2}') && \
    ./configure --with-compat --add-dynamic-module=ngx_http_geoip2_module && \
    make modules && \
    cp objs/ngx_http_geoip2_module.so /etc/nginx/modules/

# Cleanup
RUN rm -rf /var/lib/apt/lists/* nginx-* ngx_http_geoip2_module


CMD ["nginx", "-g", "daemon off;"]
FROM nginx:alpine

# Install necessary packages
RUN apk add --no-cache \
    build-base \
    pcre-dev \
    zlib-dev \
    linux-headers \
    libressl-dev \
    libmaxminddb-dev \
    git

# Download Nginx source code matching installed version
RUN nginx_version=$(nginx -v 2>&1 | awk -F/ '{print $2}') && \
    wget http://nginx.org/download/nginx-${nginx_version}.tar.gz && \
    tar -xzf nginx-${nginx_version}.tar.gz && \
    cd nginx-${nginx_version} && \
    git clone https://github.com/leev/ngx_http_geoip2_module.git

# Build the module
RUN cd nginx-$(nginx -v 2>&1 | awk -F/ '{print $2}') && \
    ./configure --with-compat --add-dynamic-module=ngx_http_geoip2_module && \
    make modules && \
    cp objs/ngx_http_geoip2_module.so /etc/nginx/modules/

# Cleanup
RUN rm -rf /var/cache/apk/* nginx-* ngx_http_geoip2_module

CMD ["nginx", "-g", "daemon off;"]
services:
  nginx:
    build: .
    container_name: nginx
    network_mode: "host"
    volumes:
      # conf files
      - ./nginx.conf:/etc/nginx/nginx.conf
      # SSL certs
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
      # logs
      - ./data/nginx/logs:/var/log/nginx
      # optional confs
      - ./conf.d:/etc/nginx/conf.d
      # GeoIP database location
      - ./data/geoip2:/usr/share/GeoIP
#    command: >
#      /bin/sh -c "apk add --no-cache nginx-mod-http-geoip2=1.26.3-r1 && nginx -g 'daemon off;'"
# if not running on host network, expose ports      
#    ports:
#      - "80:80"
#      - "443:443"
    depends_on:
      - certbot
      - geoip-updater

  geoip-updater:
    image: maxmindinc/geoipupdate:latest
    container_name: geoip-updater
    volumes:
      - ./data/geoip2:/usr/share/GeoIP
    environment:
      GEOIPUPDATE_ACCOUNT_ID: ${GEOIP_ACCOUNT_ID}
      GEOIPUPDATE_LICENSE_KEY: ${GEOIP_LICENSE_KEY}
      GEOIPUPDATE_EDITION_IDS: ${GEOIP_EDITION_IDS}
    restart: on-failure

  certbot:
    image: certbot/dns-cloudflare  # Certbot with Cloudflare DNS plugin
    container_name: certbot
    network_mode: "host"
    volumes:
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
      - ./cloudflare.ini:/etc/letsencrypt/cloudflare.ini  # Cloudflare credentials
    entrypoint: >
      /bin/sh -c "
      certbot certonly --non-interactive --quiet --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
      --email ${EMAIL} --agree-tos --no-eff-email --expand \
      --domains ${DOMAINS};

      while :; do 
        certbot renew --non-interactive --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini;
        sleep 24h;
      done"

Timers on host

Hot reload nginx

/usr/bin/docker exec nginx nginx -s reload

Update the GeoIP database (simply taking the container back up)

/usr/bin/docker compose -f /home/thomas/docker/nginx/docker-compose.yml up -d geoip-updater
/usr/bin/docker exec certbot certbot renew --non-interactive --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini;

Frequently used commands

Prune docker images

docker system prune -a

Docker compose up with build

docker compose up --build -d

Comments