Heesung Yang

How to secure nginx docker container

Goal

Prepare conf file

nginx.conf

worker_processes  1;

error_log  /dev/stderr warn;
pid        /tmp/nginx.pid;


events {
    worker_connections  1024;
}


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

    log_format  main  '$remote_addr $status $request_time "$request" '
                      '$body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';


    access_log  /dev/stdout  main;

    sendfile        on;

    keepalive_timeout  65;

    error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 /error.html;
    error_page 415 416 417 418 421 422 423 424 425 426 428 429 431 451 /error.html;
    error_page 500 501 502 503 504 505 506 507 508 510 511 /error.html;

    client_body_temp_path /tmp/client_temp;
    proxy_temp_path       /tmp/proxy_temp_path;
    fastcgi_temp_path     /tmp/fastcgi_temp;
    uwsgi_temp_path       /tmp/uwsgi_temp;
    scgi_temp_path        /tmp/scgi_temp;

    include /etc/nginx/conf.d/*.conf;
}

app.conf

server {

    listen 8000 default_server;
    server_tokens off;

    location /error.html {
        root /usr/share/nginx/html;
        internal;
    }

    location / {
        proxy_pass http://app:8000;
        proxy_redirect off;
        proxy_read_timeout 300s;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        limit_except GET POST PUT DELETE {
            deny all;
        }

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
    }
}

error.html

<!DOCTYPE html>
<html>
    <head></head>
    <body>
        <h1>Oops!</h1>
        <p>Something went wrong</p>
    </body>
</html>

Build docker image

Dockerfile

FROM nginx:1.20.1

COPY ./nginx.conf /etc/nginx/nginx.conf
COPY ./app.conf /etc/nginx/conf.d/default.conf
COPY ./error.html /usr/share/nginx/html/error.html

USER nginx
CMD nginx -g 'daemon off;'

Build

~$ docker build -t secure-nginx:1.20.1-1 .

docker-compose.yml

version: '3'
services:
  nginx:
    image: secure-nginx:1.20.1-1
    read_only: true
    user: nginx
    ports:
      - 80:8000
    tmpfs:
      - /tmp
    cap_drop:
      - ALL
    cap_add:
      - cap_net_bind_service

References