invoiceninja / dockerfiles

Docker files for Invoice Ninja
https://hub.docker.com/r/invoiceninja/invoiceninja
GNU General Public License v2.0
418 stars 268 forks source link

dockerhub page says port 80 is opened, but it's port 9000 fcgi that is opened #546

Open BloodyIron opened 1 year ago

BloodyIron commented 1 year ago

The documentation on the dockerhub page for this image series ( https://hub.docker.com/r/invoiceninja/invoiceninja ) says that port 80 is opened by the image. This is not only false, it's misleading. The only port that I can see being opened is 9000 and is fast cgi, which needs to have certain considerations for operation.

This documentation GROSSLY needs updating for many other reasons too, like it mentions PHP 7.2...

wstack-dev commented 1 year ago

I can confirm that I'm experiencing similar issues. The Docker log indicates that the expected port is not being exposed as per the documentation. Here is the Docker log output for reference:

[Entrypoint]: Initialising Invoice Ninja...

   INFO  Configuration cached successfully.  

   INFO  Caching the framework bootstrap files.  

  config ........................................................... 60ms DONE
  routes ........................................................... 82ms DONE

   INFO  Discovering packages.  

  imdhemy/laravel-purchases ............................................. DONE
  intervention/image .................................................... DONE
  invoiceninja/inspector ................................................ DONE
  laravel/slack-notification-channel .................................... DONE
  laravel/socialite ..................................................... DONE
  laravel/tinker ........................................................ DONE
  laravel/ui ............................................................ DONE
  livewire/livewire ..................................................... DONE
  nesbot/carbon ......................................................... DONE
  nunomaduro/termwind ................................................... DONE
  nwidart/laravel-modules ............................................... DONE
  sentry/sentry-laravel ................................................. DONE
  socialiteproviders/manager ............................................ DONE
  spatie/laravel-data ................................................... DONE
  turbo124/beacon ....................................................... DONE
  webpatser/laravel-countries ........................................... DONE

In Connection.php line 822:

  SQLSTATE[HY000] [2002] No such file or directory (Connection: mysql, SQL: s  
  elect * from information_schema.tables where table_schema = ninja and table  
  _name = accounts and table_type = 'BASE TABLE')                              

In Connector.php line 65:

  SQLSTATE[HY000] [2002] No such file or directory  

It appears that the documentation might not accurately reflect the current behavior of the Docker image, particularly with respect to the ports being exposed and the PHP version specified. Any guidance on this would be helpful.

BloodyIron commented 1 year ago

I speculate the port 80 thing might be before the docker image shifted to serving PHP-FPM (or equivalent) since so far as I can tell the current docker images only serve PHP-FPM services (and on port 9000), hence needing another nginx in-front of it to serve the other content too (non php files, and manage the php content sent to the PHP-FPM in the docker image).

jumban commented 10 months ago

I just followed the instructions in the https://github.com/invoiceninja/dockerfiles page using docker compose, and I am getting the same errors shown here when I checked the logs for the app container.

May I know what I need to update in order to get the application running? Thank you.

BloodyIron commented 10 months ago

From what I've seen, the exposed port 9000 service is PHP-FPM or roughly equivalent. So you will need to stick something in front of it (like nginx, but others can work) to handle incoming HTTP(S) traffic, and then be configured to use the invoiceNinja container for PHP-FPM functionality for the tool. In my case I added a side-car/secondary container for nginx to do this.

Really aggravating that the documentation is so egregiously out of date with the actual behaviour of the container. It's not even a lot of work to change that documentation (which frankly isn't my job). So yeah, we (myself + others) have to resort to cobbling it together ourselves with half-assed and incomplete documentation.

jumban commented 10 months ago

Thanks for the prompt response, I greatly appreciate it. Unfortunately, I am not a very technical person so this is a little hard for me to follow. Do you think you can give me a bit more guidance on how I can get it running?

I am trying to host Invoice Ninja from my Synology using docker, and I am using Synology's built-in nginx reverse proxy.

In my docker-compose.yml which I have taken from the official docs, I have the following:

services:
  server:
    image: nginx
    restart: always
    env_file: env
    volumes:
      # Vhost configuration
      #- ./config/caddy/Caddyfile:/etc/caddy/Caddyfiledocker-com
      - ./config/nginx/in-vhost.conf:/etc/nginx/conf.d/in-vhost.conf:ro
      - ./docker/app/public:/var/www/app/public:ro
    depends_on:
      - app
    # Run webserver nginx on port 80
    # Feel free to modify depending what port is already occupied
    ports:
      - "8001:80"
      # - "443:443"
    networks:
      - invoiceninja
    # extra_hosts:
    #   - "in5.localhost:192.168.0.124 " #host and ip

And in my reverse proxy, I had it set to redirect from https://myurl to localhost:8001 .

How should I be setting it up instead?

Thank you very much again for your help.

Samekas123 commented 10 months ago

From what I've seen, the exposed port 9000 service is PHP-FPM or roughly equivalent. So you will need to stick something in front of it (like nginx, but others can work) to handle incoming HTTP(S) traffic, and then be configured to use the invoiceNinja container for PHP-FPM functionality for the tool. In my case I added a side-car/secondary container for nginx to do this.

Really aggravating that the documentation is so egregiously out of date with the actual behaviour of the container. It's not even a lot of work to change that documentation (which frankly isn't my job). So yeah, we (myself + others) have to resort to cobbling it together ourselves with half-assed and incomplete documentation.

Also having the same problem, I don't know how to do that :(

NathanaelA commented 9 months ago

For those who might care this is how I got it working on my setup where the only part of the image I wanted was the ninja invoice as I am running nginx and mysql on the host in front of multiple docker images and other sites.

nginx settings:

   # Redirect to SSL
    server {
      listen _YOUR_SERVER_IP_:80;
      server_name _YOUR_DOMAIN_NAME_;
      return 301 https://_YOUR_DOMAIN_NAME_$request_uri;
    }

  # SSL Server
   server {
        listen _YOUR_SERVER_IP_:443 ssl http2;
        server_name _YOUR_DOMAIN_NAME_;

        # Assuming your using Lets-Encrypt for your server SSL
    ssl_certificate /etc/letsencrypt/live/_SERVER_NAME_/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/_SERVER_NAME_/privkey.pem;

        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 1h;
        ssl_buffer_size 1400;

        error_page 502  /errors/502.html;

    location ~ /\.git {
          return 404;
    }

    location ~* /storage/.*\.php$ {
            return 503;
    }

         # DO NOT CHANGE THIS "ROOT" PATH, IT MUST MATCH THE INTERNAL FIXED DOCKER INVOICE NINJA WEB PATH.
     root /var/www/app/public/;
     index index.php;

      location / {
         try_files $uri $uri/ /index.php?$query_string;
      }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

        location ~ \.php$ {

                # 9000 is the default port, but if you run php-fpm on your server this port should be 
                #     changed to match the port you want to use via the docker-compose.yml port
            fastcgi_pass localhost:9000;    

        fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_intercept_errors off;
            fastcgi_buffer_size 16k;
            fastcgi_buffers 4 16k;
      }
    }

Docker-compose.yml

version: '3.7'

services:
  app:
    image: invoiceninja/invoiceninja:latest
    env_file: env
    restart: unless-stopped
    volumes:
      - /var/www/app/public:/var/www/app/public:rw,delegated
      - /var/www/app/storage:/var/www/app/storage:rw,delegated
      - ./config/php/php.ini:/usr/local/etc/php/php.ini
      - ./config/php/php-cli.ini:/usr/local/etc/php/php-cli.ini
    ports:
      - 9000:9000

Please note a couple things:

  1. If is CRITICAL that your public directory be at /var/www/app/public Nginx needs to have the EXACT same path as PHP uses. At this point you can't change the dockers public directory. So this is a fixed value!!! This public directory will be automatically seeded/filled by the invoice ninja when it starts up so that nginx can serve static files like the css/js/images.
  2. it is also critical that the ports match, so if you changed the docker file to - 9005:9000 then in the Nginx configuration you need to use port 9005.
  3. I also copied the two php config files from this repo and dropped them into ./config/php in this docker app folder.
  4. Port 9000 is a FastCGI/FPM port, it is NOT a browsable/http port, this is why you have to have Nginx in front of it and communicating with it using its own FastCGI/FPM protocol.

Now in my case, I actually created a symlink at /var/www/app/public to point to where I actually store my public files as I prefer to keep them with the app docker folder so the storage&public files actually live physically else where. Nginx must still be pointed and be able to see the files in that folder /var/www/app/public (hence using a symlink here) or it can't pass on the php requests properly or serve any of the static files..

BloodyIron commented 9 months ago

For those who might care this is how I got it working on my setup where the only part of the image I wanted was the ninja invoice as I am running nginx and mysql on the host in front of multiple docker images and other sites.

nginx settings:

   # Redirect to SSL
    server {
      listen _YOUR_SERVER_IP_:80;
      server_name _YOUR_DOMAIN_NAME_;
      return 301 https://_YOUR_DOMAIN_NAME_$request_uri;
    }

  # SSL Server
   server {
        listen _YOUR_SERVER_IP_:443 ssl http2;
        server_name _YOUR_DOMAIN_NAME_;

        # Assuming your using Lets-Encrypt for your server SSL
  ssl_certificate /etc/letsencrypt/live/_SERVER_NAME_/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/_SERVER_NAME_/privkey.pem;

        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 1h;
        ssl_buffer_size 1400;

        error_page 502  /errors/502.html;

  location ~ /\.git {
          return 404;
  }

  location ~* /storage/.*\.php$ {
            return 503;
  }

         # DO NOT CHANGE THIS "ROOT" PATH, IT MUST MATCH THE INTERNAL FIXED DOCKER INVOICE NINJA WEB PATH.
   root /var/www/app/public/;
   index index.php;

    location / {
       try_files $uri $uri/ /index.php?$query_string;
    }

  location = /favicon.ico { access_log off; log_not_found off; }
  location = /robots.txt  { access_log off; log_not_found off; }

        location ~ \.php$ {

                # 9000 is the default port, but if you run php-fpm on your server this port should be 
                #     changed to match the port you want to use via the docker-compose.yml port
          fastcgi_pass localhost:9000;    

      fastcgi_split_path_info ^(.+\.php)(/.+)$;
          fastcgi_index index.php;
          include fastcgi_params;
          fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
          fastcgi_intercept_errors off;
          fastcgi_buffer_size 16k;
          fastcgi_buffers 4 16k;
    }
    }

Docker-compose.yml

version: '3.7'

services:
  app:
    image: invoiceninja/invoiceninja:latest
    env_file: env
    restart: unless-stopped
    volumes:
      - /var/www/app/public:/var/www/app/public:rw,delegated
      - /var/www/app/storage:/var/www/app/storage:rw,delegated
      - ./config/php/php.ini:/usr/local/etc/php/php.ini
      - ./config/php/php-cli.ini:/usr/local/etc/php/php-cli.ini
    ports:
      - 9000:9000

Please note a couple things:

  1. If is CRITICAL that your public directory be at /var/www/app/public Nginx needs to have the EXACT same path as PHP uses. At this point you can't change the dockers public directory. So this is a fixed value!!! This public directory will be automatically seeded/filled by the invoice ninja when it starts up so that nginx can serve static files like the css/js/images.
  2. it is also critical that the ports match, so if you changed the docker file to - 9005:9000 then in the Nginx configuration you need to use port 9005.
  3. I also copied the two php config files from this repo and dropped them into ./config/php in this docker app folder.
  4. Port 9000 is a FastCGI/FPM port, it is NOT a browsable/http port, this is why you have to have Nginx in front of it and communicating with it using its own FastCGI/FPM protocol.

Now in my case, I actually created a symlink at /var/www/app/public to point to where I actually store my public files as I prefer to keep them with the app docker folder so the storage&public files actually live physically else where. Nginx must still be pointed and be able to see the files in that folder /var/www/app/public (hence using a symlink here) or it can't pass on the php requests properly or serve any of the static files..

Are you running it in kubernetes/k8s?

If so, would you mind sharing a first-page-load waterfall? I'm asking because my k8s setup, while working, the initial load is still PAINNNNNNNN.

NathanaelA commented 9 months ago

No just a simple docker container. But I can tell you my first load is fairly fast lest than 2 seconds (was my total waterfall time after emptying the entire cache, so a totally fresh load) and I also have another task in the background downloading so normally it is way faster than 2 secs

Daniel15 commented 5 months ago

Most Docker containers that run PHP apps serve HTTP from the container, so that the container can be treated as a black box and the user does not have to care about its exact implementation. For example, see https://hub.docker.com/r/linuxserver/freshrss.

Serving php-fpm from the container is an interesting approach, as it's exposing an internal implementation detail that someone using the container shouldn't have to know (and that could change in the future). Not sure why it was designed this way.

BloodyIron commented 4 months ago

So I came back to this topic and I see on this page: https://hub.docker.com/r/invoiceninja/invoiceninja/

"Please note the following instructions are only for Invoice Ninja v4

For version 5 we have a docker compose file which bundles db / nginx / application which can be found here"

Why even have those instructions on that page for an EXTREMELY OLD VERSION OF INVOICENINJA???

Like, I updated my running image in k8s and the Web App upgrade button is exposed now... but it breaks with an error that I cannot find any documentation on... Is ANYONE bothering with documentation at all now for invoiceNinja???