[Docker] [Caddy] [FPM] Notify_push: can't connect to push server with nextcloud FPM image

Nextcloud version: 29.0.6
Operating system and version: Ubuntu 22.04.5 LTS
Caddy version: v2.8.4

The issue you are facing:

I am not able to activate Notify_Push with Nextcloud 29.0.6-fpm and Caddy.
The error message in the terminal reads:

$ docker compose exec app sh -c 'php occ notify_push:setup https://${OVERWRITEHOST}/push'
βœ“ redis is configured
πŸ—΄ can't connect to push server: cURL error 52: Empty reply from server (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://nextcloud.example.com/push/test/cookie

The Docker container of notify_push reports:

app-1 | 172.19.0.4 - 18/Sep/2024:11:50:55 +0200 β€œGET /index.php” 200
notify_push-1 | [2024-09-18 11:51:01.017412 +02:00] DEBUG [notify_push] /build/source/src/lib.rs:439: Test cookie received 895376949
app-1 | 172.19.0.4 - 18/Sep/2024:11:51:01 +0200 β€œGET /index.php” 200

Differentiation between FPM and non-FPM setup:

The basis is the guide β€œNextcloud docker-compose setup with notify_push (2024)”.

To use Nextcloud with FPM, I perform the following steps:

  1. change the variable NEXTCLOUD_VERSION=29.0.6 to NEXTCLOUD_VERSION=29.0.6-fpm in .env
  2. add Caddy to the Nextcloud docker-compose and create the subfolder docker/nextcloud/web, with Caddyfile as web server. The separate Caddy under /docker/caddy remains, it continues to serve as a reverse proxy.

File structure:

/docker/
β”œβ”€β”€ caddy
β”‚   β”œβ”€β”€ Caddyfile
β”‚   β”œβ”€β”€ config
β”‚   β”œβ”€β”€ data
β”‚   β”œβ”€β”€ docker-compose.yml
β”‚   β”œβ”€β”€ .env
β”‚   └── logs
└── nextcloud
    β”œβ”€β”€ apps
    β”œβ”€β”€ web
    β”‚   β”œβ”€β”€ Caddyfile
    β”‚   β”œβ”€β”€ config
    β”‚   └── data
    β”œβ”€β”€ config
    β”œβ”€β”€ cron.sh
    β”œβ”€β”€ data
    β”œβ”€β”€ db
    β”œβ”€β”€ docker-compose.yaml
    β”œβ”€β”€ .env
    β”œβ”€β”€ nextcloud
    β”œβ”€β”€ nextcloud.env
    β”œβ”€β”€ redis-session.ini
    β”œβ”€β”€ remoteip.conf
    └── secrets
        β”œβ”€β”€ nextcloud_admin_password
        β”œβ”€β”€ nextcloud_admin_user
        β”œβ”€β”€ postgres_db
        β”œβ”€β”€ postgres_password
        β”œβ”€β”€ postgres_user
        └── redis_password

[FPM] Docker compose:

networks:
  proxy:
    external: true

secrets:
  nextcloud_admin_password:
    file: ./secrets/nextcloud_admin_password # put admin password in this file
  nextcloud_admin_user:
    file: ./secrets/nextcloud_admin_user     # put admin username in this file
  postgres_db:
    file: ./secrets/postgres_db              # put postgresql db name in this file
  postgres_password:
    file: ./secrets/postgres_password        # put postgresql password in this file
  postgres_user:
    file: ./secrets/postgres_user            # put postgresql username in this file
  redis_password:
    file: ./secrets/redis_password           # put redis password in this file

services:
  web:
    image: Caddy:alpine
    pull_policy: always
    restart: unless-stopped
    volumes:
      - ./web/Caddyfile:/etc/caddy/Caddyfile
      - ./web/data:/data
      - ./web/config:/config
      - ./nextcloud:/var/www/html:ro
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
    logging:
      options:
        max-size: ${DOCKER_LOGGING_MAX_SIZE:?DOCKER_LOGGING_MAX_SIZE not set}
        max-file: ${DOCKER_LOGGING_MAX_FILE:?DOCKER_LOGGING_MAX_FILE not set}
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "127.0.0.1:2019/metrics"]
      interval: 10s
      retries: 3
      start_period: 5s
      timeout: 5s
    networks:
      - default
      - proxy

  app:
    image: nextcloud:${NEXTCLOUD_VERSION}
    restart: unless-stopped
    user: ${UID}:${GID}
    ports:
      - 127.0.0.1:9000:9000
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    env_file:
      - ./nextcloud.env
    secrets:
      - postgres_db
      - postgres_password
      - postgres_user
      - nextcloud_admin_user
      - nextcloud_admin_password
      - redis_password
    volumes:
      - ./nextcloud:/var/www/html
      - ./apps:/var/www/html/custom_apps
      - ./data:/var/www/html/data
      - ./config:/var/www/html/config
      # https://github.com/nextcloud/docker/issues/182
      - ./redis-session.ini:/usr/local/etc/php/conf.d/redis-session.ini
      - ./remoteip.conf:/etc/apache2/conf-available/remoteip.conf:ro
      - ./apache2.conf:/etc/apache2/apache2.conf
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
    networks:
      - default
        #      - proxy

  db:
    # https://hub.docker.com/_/postgres
    image: postgres:15
    restart: unless-stopped
    user: ${UID}:${GID}
    environment:
      - POSTGRES_DB_FILE=/run/secrets/postgres_db
      - POSTGRES_USER_FILE=/run/secrets/postgres_user
      - POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password
    volumes:
      - ./db:/var/lib/postgresql/data
      - /etc/passwd:/etc/passwd:ro
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d `cat $$POSTGRES_DB_FILE` -U `cat $$POSTGRES_USER_FILE`"]
      start_period: 15s
      interval: 30s
      retries: 3
      timeout: 5s
    secrets:
      - postgres_db
      - postgres_password
      - postgres_user

  cron:
    image: nextcloud:${NEXTCLOUD_VERSION}
    restart: unless-stopped
    # special UID handling https://github.com/nextcloud/docker/issues/1740
    environment:
      - UID=${UID}
    depends_on:
      - app
    env_file:
      - ./nextcloud.env
    entrypoint: /cron.sh
    volumes:
      - ./nextcloud:/var/www/html
      - ./apps:/var/www/html/custom_apps
      - ./data:/var/www/html/data
      - ./config:/var/www/html/config
      - ./cron.sh:/cron.sh
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro

  redis:
    image: redis:bookworm
    command: bash -c 'redis-server --requirepass "$$(cat /run/secrets/redis_password)"'
    secrets:
      - redis_password
    healthcheck:
      test: ["CMD-SHELL", "redis-cli --no-auth-warning -a \"$$(cat /run/secrets/redis_password)\" ping | grep PONG"]
      start_period: 10s
      interval: 30s
      retries: 3
      timeout: 3s

  notify_push:
    image: nextcloud:${NEXTCLOUD_VERSION}
    restart: unless-stopped
    user: ${UID}:${GID}
    ports:
      - 7867:7867
    depends_on:
      - app
    environment:
      - PORT=7867
      - NEXTCLOUD_URL=http://web        # don't go through the proxy to contact the nextcloud server
    entrypoint: /var/www/html/custom_apps/notify_push/bin/x86_64/notify_push /var/www/html/config/config.php
    volumes:
      # :ro ?
      - ./apps:/var/www/html/custom_apps
      - ./config:/var/www/html/config
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
    networks:
      - proxy
      - default

  imaginary:
    image: nextcloud/aio-imaginary:latest
    restart: unless-stopped
    user: ${UID}:${GID}
    expose:
      - "9000"
    depends_on:
      - app
    #environment:
    #  - TZ=${TIMEZONE} # e.g. Europe/Berlin
    cap_add:
      - SYS_NICE
    tmpfs:
      - /tmp

[FPM] Caddyfile as the web server /docker/nextcloud/web:

# Nextcloud
:80 {
   handle_path /push/* {
      reverse_proxy http://notify_push:7867
   }

   root * /var/www/html
   file_server

   php_fastcgi app:9000

   # .htaccess / data / config / ... shouldn't be accessible from outside
   @forbidden {
      path    /.htaccess
      path    /data/*
      path    /config/*
      path    /db_structure
      path    /.xml
      path    /README
      path    /3rdparty/*
      path    /lib/*
      path    /templates/*
      path    /occ
      path    /console.php
   }

   respond @forbidden 404
}

[FPM] Caddyfile as the proxy /docker/caddy

{
	servers {
		trusted_proxies static 192.168.80.1/32
	}

	email info@example.com
}

# Nextcloud
nextcloud.example.com {
	reverse_proxy http://web:80

	handle_path /push/* {	
		reverse_proxy http://notify_push:7867
	}
}

[FPM] config.php

<?php
$CONFIG = array (
  'memcache.local' => '\\OC\\Memcache\\APCu',
  'apps_paths' => 
  array (
    0 => 
    array (
      'path' => '/var/www/html/apps',
      'url' => '/apps',
      'writable' => false,
    ),
    1 => 
    array (
      'path' => '/var/www/html/custom_apps',
      'url' => '/custom_apps',
      'writable' => true,
    ),
  ),
  'memcache.distributed' => '\\OC\\Memcache\\Redis',
  'memcache.locking' => '\\OC\\Memcache\\Redis',
  'redis' => 
  array (
    'host' => 'redis',
    'password' => 'omitted',
    'port' => 6379,
  ),
  'overwritehost' => 'nextcloud.example.com',
  'overwriteprotocol' => 'https',
  'trusted_proxies' => 
  array (
    0 => '172.16.0.0/12',
    1 => '192.168.0.0/16',
    2 => '10.0.0.0/8',
    3 => 'fc00::/7',
    4 => 'fe80::/10',
    5 => '2001:db8::/32',
  ),
  'upgrade.disable-web' => true,
  'passwordsalt' => 'omitted',
  'secret' => 'omitted',
  'overwrite.cli.url' => 'https://nextcloud.example.com',
  'trusted_domains' => 
  array (
    0 => 'localhost',
    1 => 'nextcloud.example.com',
  ),
  'datadirectory' => '/var/www/html/data',
  'dbtype' => 'pgsql',
  'version' => '29.0.6.1',
  'dbname' => 'nextcloud',
  'dbhost' => 'db',
  'dbport' => '',
  'dbtableprefix' => 'oc_',
  'dbuser' => 'oc_admin',
  'dbpassword' => 'omitted',
  'installed' => true,
  'instanceid' => 'omitted',
);

What works is the following setup with image 29.0.6

  • I followed the instructions β€œNextcloud docker-compose setup with notify_push (2024)”.
    • docker compose is located under /docker/nextcloud/docker-compose.yaml.
  • I use Caddy as a reverse proxy.
    • In the setup, Caddy is a separate docker-compose under /docker/caddy/docker-compose.yaml.
    • Unlike in the setup with FPM, I don’t need a web server. Therefore, Caddy only exists once in this constellation.

The following docker compose and the Caddyfile work in the constellation. And I can configure notify_push with the command $ docker compose exec app sh -c 'php occ notify_push:setup https://${OVERWRITEHOST}/push'.

[non-FPM] Docker compose:

networks:
  proxy:
    external: true

secrets:
  nextcloud_admin_password:
    file: ./secrets/nextcloud_admin_password # put admin password in this file
  nextcloud_admin_user:
    file: ./secrets/nextcloud_admin_user     # put admin username in this file
  postgres_db:
    file: ./secrets/postgres_db              # put postgresql db name in this file
  postgres_password:
    file: ./secrets/postgres_password        # put postgresql password in this file
  postgres_user:
    file: ./secrets/postgres_user            # put postgresql username in this file

services:
  app:
    image: nextcloud:${NEXTCLOUD_VERSION}
    restart: unless-stopped
    user: ${UID}:${GID}
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    env_file:
      - ./nextcloud.env
    secrets:
      - postgres_db
      - postgres_password
      - postgres_user
      - nextcloud_admin_user
      - nextcloud_admin_password
    volumes:
      - ./nextcloud:/var/www/html
      - ./apps:/var/www/html/custom_apps
      - ./data:/var/www/html/data
      - ./config:/var/www/html/config
      # https://github.com/nextcloud/docker/issues/182
      - ./redis-session.ini:/usr/local/etc/php/conf.d/redis-session.ini
      - ./remoteip.conf:/etc/apache2/conf-available/remoteip.conf:ro
      - ./apache2.conf:/etc/apache2/apache2.conf
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
    networks:
      - proxy
      - default

  db:
    # https://hub.docker.com/_/postgres
    image: postgres:15
    restart: unless-stopped
    user: ${UID}:${GID}
    environment:
      - POSTGRES_DB_FILE=/run/secrets/postgres_db
      - POSTGRES_USER_FILE=/run/secrets/postgres_user
      - POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password
    volumes:
      - ./db:/var/lib/postgresql/data
      - /etc/passwd:/etc/passwd:ro
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d `cat $$POSTGRES_DB_FILE` -U `cat $$POSTGRES_USER_FILE`"]
      start_period: 15s
      interval: 30s
      retries: 3
      timeout: 5s
    secrets:
      - postgres_db
      - postgres_password
      - postgres_user

  cron:
    image: nextcloud:${NEXTCLOUD_VERSION}
    restart: unless-stopped
    # special UID handling https://github.com/nextcloud/docker/issues/1740
    environment:
      - UID=${UID}
    depends_on:
      - app
    env_file:
      - ./nextcloud.env
    entrypoint: /cron.sh
    volumes:
      - ./nextcloud:/var/www/html
      - ./apps:/var/www/html/custom_apps
      - ./data:/var/www/html/data
      - ./config:/var/www/html/config
      - ./cron.sh:/cron.sh
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro

  redis:
    image: redis:bookworm
    restart: unless-stopped
    # doesn't work so far :(
	  #user: ${UID}:${GID}
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
      start_period: 10s
      interval: 30s
      retries: 3
      timeout: 3s

  notify_push:
    image: nextcloud:${NEXTCLOUD_VERSION}
    restart: unless-stopped
    user: ${UID}:${GID}
    depends_on:
      - app
    environment:
      - PORT=7867
      - NEXTCLOUD_URL=http://app        # don't go through the proxy to contact the nextcloud server
    entrypoint: /var/www/html/custom_apps/notify_push/bin/x86_64/notify_push /var/www/html/config/config.php
    volumes:
      - ./apps:/var/www/html/custom_apps
      - ./config:/var/www/html/config
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
    networks:
      - proxy
      - default

  imaginary:
    image: nextcloud/aio-imaginary:latest
    restart: unless-stopped
    user: ${UID}:${GID}
    expose:
      - "9000"
    depends_on:
      - app
    #environment:
    #  - TZ=${TIMEZONE} # e.g. Europe/Berlin
    cap_add:
      - SYS_NICE
    tmpfs:
      - /tmp

[non-FPM] Caddyfile as the proxy /docker/caddy

{
	servers {
		trusted_proxies static 192.168.80.1/32
	}

	email info@example.com
}

# Nextcloud
nextcloud.example.com {
   header Strict-Transport-Security max-age=15552000;

   encode zstd gzip

   redir /.well-known/carddav /remote.php/dav 301
   redir /.well-known/caldav /remote.php/dav 301

   handle_path /push/* {
      reverse_proxy http://notify_push:7867
   }

   reverse_proxy http://app:80 # :9001

   @forbidden {
        path    /.htaccess
        path    /data/*
        path    /config/*
        path    /db_structure
        path    /.xml
        path    /README
        path    /3rdparty/*
        path    /lib/*
        path    /templates/*
        path    /occ
        path    /console.php
   }
   respond @forbidden 404
}

Notify_push uses websockets. Does Caddy also proxy websocket with your configuration? I don’t know for Caddy, but usually for Apache and Nginx you need additional configuration for websocket support.

I assume, that the proxy for the websocket works, because the non-fpm image works with caddy. I only needed to add this to the reverse proxy:

handle_path /push/* {
      reverse_proxy http://notify_push:7867
   }

However, if I use the fpm image, I need another webserver and with caddy, it will not work anymore. However, I also tried to use NGINX as the webserver for Nextcloud, it will also fail.

I solved it. The main reason, why it was not working was Caddy, as I only allowed a specific IP range to access the FQDN. This resulted in a

πŸ—΄ can't connect to push server: cURL error 52: Empty reply from server (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for nextcloud.example.com

Then I allowed all other IPs of my local network to access the FQDN, I got an

πŸ—΄ can't connect to push server: Server error: `GET https://nextcloud.example.com/push/test/cookie` resulted in a `502 Bad Gateway` response

I edited the Caddyfiles, and solved it. These are the Caddyfiles:

Caddyfile for web server:

{
        servers {
                trusted_proxies static 172.16.0.0/12
        }
}

:80 {
        handle_path /push/* {
                reverse_proxy http://notify_push:7867
        }

        root * /var/www/html
        file_server

        php_fastcgi app:9000

        redir /.well-known/carddav /remote.php/dav/ 301
        redir /.well-known/caldav /remote.php/dav/ 301

        # .htaccess / data / config / ... shouldn't be accessible from outside
        @forbidden {
                path /.htaccess
                path /data/*
                path /config/*
                path /db_structure
                path /.xml
                path /README
                path /3rdparty/*
                path /lib/*
                path /templates/*
                path /occ
                path /console.php
        }

        respond @forbidden 404
}

Caddyfile for proxy server:

{
        servers {
                trusted_proxies static 192.168.80.1/32
        }

        email info@example.com
}

# Nextcloud
nextcloud.example.com {
        redir /.well-known/carddav /remote.php/dav/ 301
        redir /.well-known/caldav /remote.php/dav/ 301

        handle_path /push/* {
                reverse_proxy notify_push:7867
        }


        header {
                Strict-Transport-Security max-age=31536000;
        }

        reverse_proxy web:80 
}
2 Likes

This topic was automatically closed 8 days after the last reply. New replies are no longer allowed.