nginxinc / docker-nginx

Official NGINX Dockerfiles
BSD 2-Clause "Simplified" License
3.25k stars 1.73k forks source link

how to build nginx with modules? #484

Closed schel4ok closed 3 years ago

schel4ok commented 3 years ago

I need ngx_http_access_module, but it is not included in docker nginx:latest. How I can install it? No instruction about it on docker hub. And here I found few issues about external modules, but no clear solution.

thresheek commented 3 years ago

It is included. It's not actually possible to build nginx without that module.

schel4ok commented 3 years ago

then why this conf gives me 500 Internal Server Error when I try to access from LAN2 ?

        allow   192.168.1.0/24;    # allow anyone in LAN1
        allow   192.168.2.0/24;    # allow anyone in LAN2
        deny    all;                # drop rest of the world

and when I check what is included I cannot find ngx_http_access_module in the list

# nginx -V
nginx version: nginx/1.19.5
built by gcc 8.3.0 (Debian 8.3.0-6)
built with OpenSSL 1.1.1d  10 Sep 2019
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -fdebug-prefix-map=/data/builder/debuild/nginx-1.19.5/debian/debuild-base/nginx-1.19.5=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie'
thresheek commented 3 years ago

The module is always built, so it's not something that can be disabled or enabled via configure line while building nginx.

Please show the full configuration and error logs from your installation after such a request results in 500.

schel4ok commented 3 years ago

Here is extract from docker-compose

  nginx:  # frontend
    container_name: nginx
    build:
      context: ./nginx
    depends_on:
      - php
    environment:
      TZ: ${WORKSPACE_TIMEZONE}
    working_dir: /var/www
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf  # основной конфиг
      - ./nginx/conf.d:/etc/nginx/conf.d          # папка с конфигами сайтов
      - ./nginx/logs:/var/log/nginx/              # папка с логами
      - ${PROJECTS}:/var/www                      # папка с сайтами
      - ${SSL_CERT_PROJECT1}:/etc/ssl/private/project1.ru
      - ${SSL_CERT_PROJECT2}:/etc/ssl/private/project2.ru
    ports:
      - 85:80
      - 450:443
    restart: always
    networks:
      - internal

nginx Dockerfile

FROM nginx:alpine

RUN addgroup -g 1014 -S http && adduser -u 1014 -D -S -G http http
# 1014 is id of my http user on host machine

RUN  mkdir -p /etc/ssl/private/project1.ru \
    && mkdir -p /etc/ssl/private/project2.ru \
    && chown -R http:http /etc/ssl/private

WORKDIR /var/www

Output file nginx -T is quite long, so I better put extracts here. In main nginx.conf file I changed only 2 things: 1) change user from nginx to http 2) uncomment gzip on; in http context.

#user  nginx;
user  http;
...
http {
    ...
    gzip  on;
    ...
}

In conf.d directory I have few conf files for each webservice. Here is the one host, which I have problems with access

# configuration file /etc/nginx/conf.d/server.conf:
server {
    listen       80 default;

    server_name server.lan mydns.ext www.mydns.ext;
    root /var/www/mydns.ext;

    # redirect  http://www.domain.ru  -> http://domain.ru
    if ($host ~* "^www\.(.*)$") {
        return 301 $scheme://$1$request_uri;
    }

    error_log /var/log/nginx/mydns.error.log;
    access_log /var/log/nginx/mydns.access.log combined if=$loggable;

    location ~ ^/adminer(/.*$|$) {
        allow   192.168.1.0/24;    # allow anyone in LAN1
        allow   192.168.2.0/24;    # allow anyone in LAN2
        deny    all;               # drop rest of the world

        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME /var/www/html/index.php; # this is the important part
        fastcgi_pass adminer:9000; # host and port goes here
    }

}

Here is the error after try to access adminer if allow and deny rules uncommented.

192.168.142.1 - - [21/Dec/2020:20:49:42 +0300] "GET /adminer HTTP/1.1" 500 579 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
192.168.142.1 - - [21/Dec/2020:20:49:43 +0300] "GET /favicon.ico HTTP/1.1" 500 579 "http://server.lan/adminer" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"

Nginx has local IP address in docker 192.168.142.3 and gateway 192.168.142.1 (this info I got from portainer) Host machine where docker installed has IP address in 192.168.1.0/24 (LAN1) and PC from where I try to access adminer has IP address in 192.168.2.0/24 (LAN2). LAN1 and LAN2 connected using VPN.

thresheek commented 3 years ago

What's in /var/log/nginx/mydns.error.log for those requests?

schel4ok commented 3 years ago

mydns.access.log

192.168.142.1 - - [22/Dec/2020:19:09:44 +0300] "GET /adminer HTTP/1.1" 500 579 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
192.168.142.1 - - [22/Dec/2020:19:09:44 +0300] "GET /favicon.ico HTTP/1.1" 500 579 "http://server.lan/adminer" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"

mydns.error.log

2020/12/22 19:09:44 [error] 199#199: *15046 access forbidden by rule, client: 192.168.142.1, server: server.lan, request: "GET /adminer HTTP/1.1", host: "server.lan"

2020/12/22 19:09:44 [error] 199#199: *15046 could not find named location "@error_page", client: 192.168.142.1, server: server.lan, request: "GET /adminer HTTP/1.1", host: "server.lan"

2020/12/22 19:09:44 [error] 199#199: *15047 open() "/var/www/mydns.ext/favicon.ico" failed (2: No such file or directory), client: 192.168.142.1, server: server.lan, request: "GET /favicon.ico HTTP/1.1", host: "server.lan", referrer: "http://server.lan/adminer"

2020/12/22 19:09:44 [error] 199#199: *15047 could not find named location "@error_page", client: 192.168.142.1, server: server.lan, request: "GET /favicon.ico HTTP/1.1", host: "server.lan", referrer: "http://server.lan/adminer"
thresheek commented 3 years ago

As you can see, error_page is triggered for 403 (access forbidden) and 404 (file not found).

As you don't have a proper location defined for it (although specified in error_page which must be somewhere in your configuration that you didnt post), nginx issues a 500s. Fix that and you'll get proper responses.

schel4ok commented 3 years ago

I have this in http context, which I believe should be applied to all hosts

error_page 400 401 402 403 404 405 406 407 408 500 501 502 503 504 505 @error_page;
thresheek commented 3 years ago

You don't have a @error_page location.

schel4ok commented 3 years ago

If I delete that string, then I see 403 Forbidden on web page and access forbidden in the log

2020/12/22 21:40:05 [error] 229#229: *15194 access forbidden by rule, client: 192.168.142.1, server: server.lan, request: "GET /adminer HTTP/1.1", host: "server.lan"

I checked that it happens only when deny all is uncommented in my configuration. But I cannot understand why this rule blocks access to me, because I am in LAN and I have allow rule before deny.

schel4ok commented 3 years ago

also if I do docker-compose exec "nginx" ls /etc/nginx/modules then I see this list

ngx_http_geoip_module-debug.so         ngx_http_xslt_filter_module-debug.so
ngx_http_geoip_module.so               ngx_http_xslt_filter_module.so
ngx_http_image_filter_module-debug.so  ngx_stream_geoip_module-debug.so
ngx_http_image_filter_module.so        ngx_stream_geoip_module.so
ngx_http_js_module-debug.so            ngx_stream_js_module-debug.so
ngx_http_js_module.so                  ngx_stream_js_module.so
thresheek commented 3 years ago

500 is not "blocking access", it's a misconfiguration of a server. With error_page 400... @error_page;, you're telling nginx to internally redirect to @error_page location when deny event happens. Since this location is not available in your configuration, nginx errors out. See http://nginx.org/en/docs/http/ngx_http_core_module.html#error_page for more details.

Regarding as to why this rule blocks you, your logs suggest that you're coming from 192.168.142.1, and not 192.168.1.0 or 192.168.2.0. You need to check your network settings & NATs to figure out why this happens.