evertramos / nginx-proxy-automation

Automated docker nginx proxy integrated with letsencrypt.
MIT License
2.66k stars 632 forks source link

[BUG] nginx return file not found with nginx-proxy #262

Closed cod3rshotout closed 3 years ago

cod3rshotout commented 3 years ago

I'm using this image to run multiple sites/app on a single nginx instance. So far, I was able to run a static site and a nodejs application without problems but I'm facing an issue with a php application created with codeigniter.

Essentially the project structure looks like this:

nginx
    nginx-proxy
       docker-compose.yml
    php-application
       docker-compose.yml

Inside the php-application/docker-compose.yml I have this:

version: '3.7'

services:
  php-fpm:
    container_name: boilerplate_app
    restart: always
    build:
      context: .
      dockerfile: ./docker/php-fpm/Dockerfile
    volumes:
      - ./src:/var/www/html
    environment:
      # NGINX-PROXY ENVIRONMENT VARIABLES: UPDATE ME
      - VIRTUAL_HOST=mysite.com
      - VIRTUAL_ROOT=/var/www/html
      - VIRTUAL_PORT=9000
      - VIRTUAL_PROTO=fastcgi
      - LETSENCRYPT_HOST=mysite.com
      - LETSENCRYPT_EMAIL=info@mysite.it
      # /END NGINX-PROXY ENVIRONMENT VARIABLES
    ports:
      - '9000:80'
    expose:
      - 9000
    networks:
      - proxy

  #nginx:
  #  container_name: boilerplate_nginx
  #  build: ./docker/nginx
  #  restart: always
  #  volumes:
  #    - ./src:/var/www/html
     # - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
     # - ./docker/nginx/sites/:/etc/nginx/sites-available
     # - ./docker/nginx/conf.d/:/etc/nginx/conf.d
  #  ports:
  #    - '8880:80'
  #  depends_on:
  #    - php-fpm
  #  networks:
  #    - proxy

  database:
    container_name: boilerplate_db
    restart: always
    build:
      context: ./docker/database
    environment:
      - MYSQL_DATABASE=boilerplate
      - MYSQL_USER=user
      - MYSQL_PASSWORD=secret
      - MYSQL_ROOT_PASSWORD=secret
    volumes:
      - ./docker/database/data.sql:/docker-entrypoint-initdb.d/data.sql

  phpmyadmin:
    container_name: boilerplate_phpmyadmin
    image: phpmyadmin/phpmyadmin
    restart: always
    ports:
      - 8088:80
    environment:
      - PMA_HOST=database
      - MYSQL_USER=user
      - MYSQL_PASSWORD=secret
      - MYSQL_ROOT_PASSWORD=secret
    depends_on:
      - database

networks:
  proxy:
    external:
      name: nginx-proxy

The php application runs over php-fpm specifically on the port 9000 using fastcgi, for this I used the following directives:

  - VIRTUAL_ROOT=/var/www/html/public
  - VIRTUAL_PORT=9000
  - VIRTUAL_PROTO=fastcgi

to make it working, I also specified the VIRTUAL_ROOT that should redirect all the request on the index.php which is available in this directory /var/www/html/public. Project structure:

php-application
    src
        node_modules
        app
        public
        tests
        vendor
        writable
        .env
        composer.json
        package.json
        spark

the problem's that when I start the php-application container using docker-compose up --build -d, I get this when I visit mysite.com (hide for privacy the real domain):

File not found.

Inspecting the nginx log using sudo docker logs -f nginx I get:

[error] 30#30: *39 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 2.38.140.109, server: mysite.com, request: "GET / HTTP/2.0", upstream: "fastcgi://172.28.0.7:9000", host: "mysite.com"
mysite.com 2.38.140.109 - - [29/Mar/2021:17:52:31 +0000] "GET / HTTP/2.0" 404 16 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.63"

what I did wrong?

UPDATE:

output of /var/log/nginx/error.lg

2021/03/30 10:53:22 [notice] 98#98: signal process started
2021/03/30 10:53:32 [warn] 99#99: no resolver defined to resolve r3.o.lencr.org while requesting certificate status, responder: r3.o.lencr.org, certificate: "/etc/nginx/certs/example.com.crt"
2021/03/30 10:53:32 [error] 99#99: *305 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 212.171.224.237, server: example.com, request: "GET / HTTP/2.0", upstream: "fastcgi://172.28.0.7:9000", host: "example.com"
2021/03/30 10:53:32 [error] 99#99: *305 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 212.171.224.237, server: example.com, request: "GET /favicon.ico HTTP/2.0", upstream: "fastcgi://172.28.0.7:9000", host: "example.com", referrer: "https://example.com/"

UPDATE 2

/etc/resolve.conf

enter image description here

evertramos commented 3 years ago

Hello @cod3rshotout!

This is not a bug in the nginx-proxy-automation... but more a config in your set up. How is your php-fpm running? Can you share your Dockerfile and entrypoint script?

You must check the settings on the fpm to respond, the proxy seems to be doing it's job.

There is a similar issue on this:

https://github.com/evertramos/nginx-proxy-automation/issues/219

I might take a took by tomorrow on that as well ok?

Meanwhile, If you find the solution, please post it here for future reference.

Thanks!

cod3rshotout commented 3 years ago

Hi @evertramos thanks for your quick reply, I've been trying to fix this issue for days without any luck. My php application has been written using CodeIgniter 4 and the app structure is the following:

php-application
   docker
       php-fpm
            config
                php.ini
           Dockerfile
   src
       node_modules
       app
       public
       tests
       vendor
       writable
       .env
       composer.json
       package.json
       spark
   docker-comopse.yml

the index.php file is available inside the public folder. The docker-compose.yml of php-application contains the following stuff:

version: '3.7'

services:
  php-fpm:
    container_name: boilerplate_app
    restart: always
    build:
      context: .
      dockerfile: ./docker/php-fpm/Dockerfile
    volumes:
      - ./src:/var/www/html
    environment:
      # NGINX-PROXY ENVIRONMENT VARIABLES: UPDATE ME
      - VIRTUAL_HOST=mysite.com
      - VIRTUAL_ROOT=/var/www/html/public
      - VIRTUAL_PORT=9000
      - VIRTUAL_PROTO=fastcgi
      - LETSENCRYPT_HOST=mysite.com
      - LETSENCRYPT_EMAIL=info@mysite.com
      - NETWORK=proxy
      # /END NGINX-PROXY ENVIRONMENT VARIABLES
    ports:
      - '9000:80'
    expose:
      - 9000
    networks:
      - proxy

  database:
    container_name: boilerplate_db
    restart: always
    build:
      context: ./docker/database
    environment:
      - MYSQL_DATABASE=boilerplate
      - MYSQL_USER=user
      - MYSQL_PASSWORD=secret
      - MYSQL_ROOT_PASSWORD=secret
    volumes:
      - ./docker/database/data.sql:/docker-entrypoint-initdb.d/data.sql

  phpmyadmin:
    container_name: boilerplate_phpmyadmin
    image: phpmyadmin/phpmyadmin
    restart: always
    ports:
      - 8088:80
    environment:
      - PMA_HOST=database
      - MYSQL_USER=user
      - MYSQL_PASSWORD=secret
      - MYSQL_ROOT_PASSWORD=secret
    depends_on:
      - database

networks:
  proxy:
    external:
      name: proxy

essentially I have three services:

The Dockerfile content of php-fpm contains the following stuff:

FROM php:8.0.2-fpm-alpine
WORKDIR /var/www/html

RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install mysqli
RUN apk add icu-dev

# Install intl
RUN docker-php-ext-configure intl && docker-php-ext-install intl

# Install curl
RUN apk add --update libzip-dev curl-dev &&\
    docker-php-ext-install curl && \
    apk del gcc g++ &&\
    rm -rf /var/cache/apk/*

COPY docker/php-fpm/config/php.ini /usr/local/etc/php/

# Install composer
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer

# Install nodejs
RUN apk add --update nodejs nodejs-npm
RUN npm install gulp-cli -g
RUN npm install

COPY src src/

CMD ["php-fpm"]

EXPOSE 9000

when I start the container using docker-compose up --build -d I get this message when I visit mysite.com (I have hidden the real domain for privacy):

FIle not found

and when I inspect the log of your image: sudo docker logs -f nginx I get:

2021/03/30 10:53:22 [notice] 98#98: signal process started
2021/03/30 10:53:32 [warn] 99#99: no resolver defined to resolve r3.o.lencr.org while requesting certificate status, responder: r3.o.lencr.org, certificate: "/etc/nginx/certs/mysite.com.crt"
2021/03/30 10:53:32 [error] 99#99: *305 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 212.171.224.237, server: mysite.com, request: "GET / HTTP/2.0", upstream: "fastcgi://172.28.0.7:9000", host: "mysite.com"
2021/03/30 10:53:32 [error] 99#99: *305 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 212.171.224.237, server: mysite.com, request: "GET /favicon.ico HTTP/2.0", upstream: "fastcgi://172.28.0.7:9000", host: "mysite.com", referrer: "https://mysite.com/"

Thanks in advance for any help.

Kind regards

cod3rshotout commented 3 years ago

Hi @evertramos another test that I did is update the nginx template with this:

https://gofile.io/d/SQl3KH

Now the "File not found" error is gone, but all the static files such js, CSS and images aren't loaded, infact I get 404.

Could you help me please?

evertramos commented 3 years ago

Hello @cod3rshotout!

Today I got some time and took me a couple hours to figure it out, but here it is, follow the steps:

1. Create a simple docker compose file as of (docker-compose.yml):

version: "3.9"

services:
  php-fpm:
    image: php:fpm-alpine3.13
    container_name: php-fpm
    volumes:
      - ./../data/site:/var/www/html
    environment:
      - VIRTUAL_HOST=[your url]
      - LETSENCRYPT_HOST=[your url]
      - VIRTUAL_PROTO=fastcgi

networks:
  default:
    external:
      name: proxy

Update '[your url]' with your own URL

This is my index.php which was in volume above:

<?php

echo "PHP FPM over nginx-proxy!";

2. Add special settings to nginx-proxy to your URL

As of quoted in the nginx proxy, we can have special setting per host as following instruction below:

Find the ./vhost.d which was binded in the proxy.

You can find the right path at _NGINX_FILESPATH variable at .env file.

The files below must be added to the right place which is ./vhost.d folder.

So, here are the files:

file 1 under the name: [your url]_location

try_files $uri $uri/ /index.php?$args;

file 2 under the name: [your url]

root   /var/www/html;
index index.php;

location ~ [^/]\.php(/|$) {
  fastcgi_split_path_info ^(.+?\.php)(/.*)$;

  include fastcgi_params;
  fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  fastcgi_param PATH_INFO       $fastcgi_path_info;
  fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

  fastcgi_pass   [your url];
  fastcgi_index  index.php;
}

Make sure to update [your url] with your domain name, in the file name and in the _fastcgipass above.

3. Fire up your docker-compose (php-fpm) and be happy! 😃

image

Sorry my late reply was in holiday these days...

cod3rshotout commented 3 years ago

Hi @evertramos many thanks for your precious help! You've helped me a lot! The file not found problem seems resolved, even with the original nginx.tmpl, so this is amazing!

I just have few questions:

  1. I have created in NGINX_FILES_PATH, specifically in the vhost.d folder two files as you suggested:

mysite.com, which contains this:

location ^~ /.well-known/acme-challenge/ {
    auth_basic off;
    auth_request off;
    allow all;
    root /usr/share/nginx/html;
    try_files $uri =404;
    break;
}
root   /var/www/html/public;
index index.php;

location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;

include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO       $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

fastcgi_pass   mysite.com
fastcgi_index  index.php;
}`

and mysite.com_location, which contains this:

try_files $uri $uri/ /index.php?$args;

inside the app which runs over php-fpm I have this docker-compose.yml content:

version: '3.9'

services:
boilerplate_app:
    container_name: boilerplate_app
    restart: always
    build:
    context: .
    dockerfile: ./docker/php-fpm/Dockerfile
    volumes:
    - ./src:/var/www/html
    - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
    - ./docker/nginx/sites/:/etc/nginx/sites-available
    - ./docker/nginx/conf.d/:/etc/nginx/conf.d
    environment:
    # NGINX-PROXY ENVIRONMENT VARIABLES: UPDATE ME
    - VIRTUAL_HOST=mysite.com
    - VIRTUAL_ROOT=/var/www/html/public
    - VIRTUAL_PORT=9000
    - VIRTUAL_PROTO=fastcgi
    - LETSENCRYPT_HOST=mysite.com
    - LETSENCRYPT_EMAIL=info@mysite.com
    # /END NGINX-PROXY ENVIRONMENT VARIABLES

when I do docker-compose up --build -d the site load correctly but all the static files such as images, js and css return 404. I did something bad or I missed something?

  1. When I have created the two files: mysite.com and mysite.com_location, I changed the vhost.d owner as my linux user instead of root is this a good practice?

Thanks again for your precious help!

Kind regards

evertramos commented 3 years ago

@cod3rshotout are you using Laravel?

If so, open a new discussion on that I will help you out there... and I will delete this last post and lock the issue. ok?

Wait on you.

cod3rshotout commented 3 years ago

@evertramos I'm using CodeIgniter 4 with this app starter:

https://github.com/agungsugiarto/boilerplate

I'have sended on this email [...] my app, may could you have a look?

Thanks again

evertramos commented 3 years ago

In order to serve the static files from a container using the nginx proxy, the nginx proxy must have access to files statically... it would not 'proxy' but 'read' and serve the files... which means you must mount the app files into the proxy... PLEASE DON'T GO THAT WAY!

I would recommend you put up a new, light and clean nginx begind the nginx proxy along with your php-fpm service so you can have full management of your routes/locations,

Here is a very simple example:

https://github.com/evertramos/nginx-behind-proxy

Hope it helps!

cod3rshotout commented 3 years ago

Thanks for the tips of @evertramos I was able to make it working.

First of all I have created a docker-compose.yml in my app that contains the following:

version: '3.9'

services:

php-fpm:
    container_name: boilerplate_app
    restart: always
    build:
    context: .
    dockerfile: ./docker/php-fpm/Dockerfile
    volumes:
    - ./src:/var/www/html

nginx:
    image: nginx:stable-alpine
    container_name: boilerplate_nginx
    restart: always
    volumes:
    - ./src:/var/www/html
    - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
    - ./docker/nginx/sites/:/etc/nginx/sites-available
    - ./docker/nginx/conf.d/:/etc/nginx/conf.d
    depends_on:
    - php-fpm
    environment:
    VIRTUAL_HOST: example.com
    LETSENCRYPT_HOST: example.com
    LETSENCRYPT_EMAIL: info@example.com

database:
    container_name: boilerplate_db
    restart: always
    build:
    context: ./docker/database
    environment:
    - MYSQL_DATABASE=boilerplate
    - MYSQL_USER=user
    - MYSQL_PASSWORD=secret
    - MYSQL_ROOT_PASSWORD=secret
    volumes:
    - ./docker/database/data.sql:/docker-entrypoint-initdb.d/data.sql

phpmyadmin:
    container_name: boilerplate_phpmyadmin
    image: phpmyadmin/phpmyadmin
    restart: always
    ports:
    - 8088:80
    environment:
    - PMA_HOST=database
    - MYSQL_USER=user
    - MYSQL_PASSWORD=secret
    - MYSQL_ROOT_PASSWORD=secret
    depends_on:
    - database

networks:
default:
    external:
    name: proxy

then, inside my app directory I have created the nginx configurations structure:

app
   docker
       nginx
           conf.d
              default.conf
           sites
              default.conf
        nginx.conf

where I have conf.d:

upstream php-upstream {
    server php-fpm:9000;
}

then I have sites:

server {
    root   /var/www/html/public;
    index index.php;

    location ~ [^/]\.php(/|$) {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;

    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO       $fastcgi_path_info;
    fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

    fastcgi_pass   php-upstream;
    fastcgi_index  index.php;
    }
}

and nginx.conf:

user  nginx;
worker_processes  4;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

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

    access_log  /var/log/nginx/access.log;
    # Switch logging to console out to view via Docker
    #access_log /dev/stdout;
    #error_log /dev/stderr;

    sendfile        on;
    keepalive_timeout  65;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-available/*.conf;
}

the site load now but there are some issues:

  1. Performance issue: we have two nginx layer here and the load time is increased a lot
  2. If I browse some url like example.com/admin I get 404 from nginx, guess it's a configuration issue on my own