'Storing docker nginx access logs inside a docker volume

Currently my docker container is printing the nginx access logs to /dev/stdout. How do I create a volume inside my docker container to store the access logs?

My Dockerfile:

FROM python:3.7

ENV APP_ROOT /src
ENV CONFIG_ROOT /config

RUN apt-get update
RUN apt-get install -y apt-utils
RUN apt-get -y install unixodbc-dev
RUN apt-get -y install default-libmysqlclient-dev

RUN mkdir ${CONFIG_ROOT}
COPY /app/requirements.txt ${CONFIG_ROOT}/requirements.txt
RUN pip install -r ${CONFIG_ROOT}/requirements.txt

RUN mkdir ${APP_ROOT}
WORKDIR ${APP_ROOT}

ADD /app/ ${APP_ROOT}

My docker-compose.yml:

version: "3"

services:
  app:
    build: .
    container_name: django-gunicorn
    restart: always
    env_file:
      - django.env
    ports:
      - "8000:8000"
    command:
      "gunicorn --workers=2 --bind=0.0.0.0:8000 mysite.wsgi:application"

  nginx:
    image: nginx:1.14
    container_name: ngx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx:/etc/nginx/conf.d
      - ./app/static:/static
    depends_on:
      - app

My nginx/default.conf:

limit_req_zone "$binary_remote_addr$request_uri" zone=one:10m rate=60r/m;

server {
    listen 80;
    server_name example.org;
    server_tokens off;

    location  /static/ {
        autoindex on;
        alias /static/;
    }

    location / {
        proxy_pass http://app:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        limit_req zone=one nodelay burst=30;

    }
}

I am trying to add fail2ban and fluentd logging to this application but first I need to store the physical file (not /dev/stout) which can be used for other logging purposes.

Thanks you!



Solution 1:[1]

By default the Nginx container forwards access logs to STDOUT and error logs to STDERR. You can see these lines in nginx Dockerfile:

# forward request and error logs to docker log collector
    && ln -sf /dev/stdout /var/log/nginx/access.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log \

So you can see nginx logs in container logs:

docker logs -f ngx

But if you want to store nginx logs in a docker volume (or a local mounted directory), first create your customized nginx docker image:

FROM nginx
RUN rm /var/log/nginx/*

And then your nginx service in docker-compose.yml would be like:

nginx:
    build: ./nginx/
    container_name: ngx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx:/etc/nginx/conf.d
      - ./app/static:/static
      - ./log/nginx:/var/log/nginx
    depends_on:
      - app

Solution 2:[2]

Apart from the comments above to add the volume, you have to adjust main Nginx configuration (most probably /etc/nginx/nginx.conf) and/or configuration files for each vhost.

In most cases add these to your main configuration:

http {
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
}

Similar entries could be palces inside server or location

Solution 3:[3]

You can still use default nginx docker file and attach volume to store log files. (Nginx allows you to log into multiple destinations at same time even using filters). ( https://docs.nginx.com/nginx/admin-guide/monitoring/logging/)

Compose file:

      volumes:
          - ./static_log/:/static_log:rw

And later specify log files multiple times:

    access_log /static_log/access.2xx.log main if=$logok;
    access_log /static_log/access.4xx.log main if=$log4xx;
    access_log /static_log/access.5xx.log main if=$log5xx;
    access_log /var/log/nginx/access.log main;

    error_log /static_log/error.log warn;
    error_log /var/log/nginx/error.log notice;

BTW: i used log filtring in http block before so 2xx (200,301) resonses goes into one file 4xx responess to a different file also.

    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;

        access_log  /var/log/nginx/access.log  main;
    ...
        map $status $logok {
            ~^[123]  1;
            default 0;
        }

        map $status $log4xx {
            ~^[4]  1;
            default 0;
        }

        map $status $log5xx {
            ~^[5]  1;
            default 0;
        }

        log_not_found on;

More info still on nginx official documentation https://docs.nginx.com/nginx/admin-guide/monitoring/logging/

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Samuel-L-29
Solution 2 Szczad
Solution 3