Setting up Kirby with nginx + docker fails - 502 Error - connect() failed (111: Connection refused) while connecting to upstream


I have huge troubles to get Kirby up and running. I have been following the guide on setting up Kirby with nginx. I am using a nginx reverse proxy (by jwilder) to host multiple websites on the same machine. With this proxy I cannot override the default nginx .conf file that is why I have added another nginx service behind that proxy.

Please have a look at my files, I am stuck since weeks.


version: '2'


      context: .
      dockerfile: Dockerfile
    image: my-image
    restart: always
      - kirby
      - 9001:9001
      - 9001
      - ./:/var/www/html

    image: nginx
    restart: always
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - nfs_subdomain
      - nfs_subdomain
      - VIRTUAL_HOST=sub.domain.tld
      - VIRTUAL_NETWORK=nginx-proxy
      - VIRTUAL_PORT=80
      - LETSENCRYPT_HOST=sub.domain.tld
      - kirby
      - proxy-tier

      name: nginxproxy_default


user www-data;

events {
  worker_connections 768;

http {
  upstream kirby_server {
    server nfs_subdomain:9001;

  include /etc/nginx/mime.types;
  default_type application/octet-stream;
  gzip on;
  gzip_disable "msie6";

  server {
    listen 9001;

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

    location / {
      try_files $uri $uri/ =404;

    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
      root /usr/share/nginx/html;

    location = /favicon.ico {
      log_not_found off;
      access_log off;

    # CSS and Javascript
    location ~* \.(?:css|js)$ {
      expires 1y;
      access_log off;
      add_header Cache-Control "public";

    location ~ \.php$ {
      fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
      fastcgi_param  SERVER_SOFTWARE    nginx;
      fastcgi_param  QUERY_STRING       $query_string;
      fastcgi_param  REQUEST_METHOD     $request_method;
      fastcgi_param  CONTENT_TYPE       $content_type;
      fastcgi_param  CONTENT_LENGTH     $content_length;
      fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
      fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
      fastcgi_param  REQUEST_URI        $request_uri;
      fastcgi_param  DOCUMENT_URI       $document_uri;
      fastcgi_param  DOCUMENT_ROOT      $document_root;
      fastcgi_param  SERVER_PROTOCOL    $server_protocol;
      fastcgi_param  REMOTE_ADDR        $remote_addr;
      fastcgi_param  REMOTE_PORT        $remote_port;
      fastcgi_param  SERVER_ADDR        $server_addr;
      fastcgi_param  SERVER_PORT        $server_port;
      fastcgi_param  SERVER_NAME        $server_name;
      fastcgi_intercept_errors on;
      fastcgi_pass kirby_server;


FROM php:7.4-fpm

# Install packages: web server & PHP plus extensions
RUN apt-get update && apt-get install -y \
  git \
  curl \
  libpng-dev \
  libonig-dev \
  zip \

RUN apt-get clean && rm -rf /var/lib/apt/lists/*

#probably only laravel stuff
RUN docker-php-ext-install pdo_mysql mbstring exif bcmath gd

#install composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
COPY composer.json composer.lock /var/www/html/
RUN composer install

WORKDIR /var/www/html

USER $user

The logfile from the docker-compose.yml file is:

nfs_subdomain_1  | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using Set the 'ServerName' directive globally to suppress this message
nfs_subdomain_1  | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using Set the 'ServerName' directive globally to suppress this message
nfs_subdomain_1  | [Thu Aug 26 10:55:54.759065 2021] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.38 (Debian) PHP/7.4.22 configured -- resuming normal operations
nfs_subdomain_1  | [Thu Aug 26 10:55:54.759092 2021] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'

And finally the error from the reverse nginx proxy:

nginx.1    | 2021/08/26 10:56:18 [error] 1563#1563: *419017 connect() failed (111: Connection refused) while connecting to upstream, client:, server: sub.domain.tld, request: "GET / HTTP/2.0", upstream: "http://xxx.xx.0.13:80/", host: "sub.domain.tld"

If I do a netstat:

netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface         UG        0 0          0 eth0   U         0 0          0 eth0
netstat -npl 
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0    *               LISTEN      1/apache2           
tcp        0      0*               LISTEN      -                   
udp     3840      0*                           - 

I suspect the problem to be somewhere close to fastcgi_pass or something like this. Keep in mind that I have a proxy running so I don’t really know if listen 9001; is correct or not. I have tried everything out that makes sense and that does not make sense…

Thank you!

i’m no expert, but isn’t it very strange that you receive log messages from apache when you’re using the fpm image?

Are you sure you’re running the image you think you are running?

Isn’t it maybe that you tried with an apache image before, like php:7.4-apache and that for some reason it didn’t rebuild the image when you changed it to fpm?
Maybe try starting fresh with a docker system prune -a (if this is your dev machine and you don’t have important stuff in any container).

Also, afaik, the fpm image listens by default on port 9000, you’re trying to connect upstream to 9001.

I also think that file volumes (your nginx config file is mounted as volume) need to use an absolute path and you are using a relative path. Not sure about this though, it’s just that I’ve always seen absolute paths for files. You can use environment variables if you want it to be portable:

      - ${PWD}/nginx/nginx.conf:/etc/nginx/nginx.conf:ro

Maybe check in the container if the file is really there (like, once it’s up, attach a shell to it and check that).

Also, I’d remove the lines:

      - 9001:9001
      - 9001

from the fpm image in the docker file, those look dangerous. You really don’t want your fpm container to be accessible from the host machine. The image itself exposes port 9000, there shouldn’t be a need to specify it in docker compose.

If listen 9001 is correct depends on how the jwilder image works. Idk that (never used it), but I’d imagine that “VIRTUAL_PORT” has to match the port on which nginx in nfs_nginx listens. Also, you probably would have to expose that port. So either set listen to “80” (which is exposed by default by the image) or change VIRTUAL_PORT to 9001, and expose 9001.

So, to summarize:

  1.  docker-compose down
     docker rm -f $(docker ps -a -q)
     docker system prune -a
  2. change docker-compose.yml and remove the “ports” and “expose” properties from the nfs_subdomain service
  3. change the nginx upstream definition to make it use server nfs_subdomain:9000
  4. change your nginx config to make it listen on port 80
  5. docker-compose up
  6. ???
  7. Profit!
1 Like

Thank you very much! I have worked so close to it that I forgot to really look into the basics. I always thought that if I have another docker-service running on port 9000 I could not use this one again. But that is why I have a reverse proxy. So I have just changed the ports removed the exposed ports from the docker-compose, added the pwd in front of the volumes and it worked. Thank you very much!

1 Like