Cloudron makes it easy to run web apps like WordPress, Nextcloud, GitLab on your server. Find out more or install now.


Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Bookmarks
  • Search
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo

Cloudron Forum

Offical apps | Community apps | Demo | Docs | Install
  1. Cloudron Forum
  2. Nextcloud
  3. Is it possible/safe to install Client Push App ?

Is it possible/safe to install Client Push App ?

Scheduled Pinned Locked Moved Nextcloud
18 Posts 8 Posters 2.9k Views 8 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A
    A
    andreasb
    wrote on last edited by andreasb
    #9

    sorry for replying late:
    there's no cron job involved, maybe that's the issue?
    Everything needs to be done manually:

    • nginx-config whenever Cloudron box is updated, in an SSH session
    • running the script to start notify_push whenever NC app is restarted, using a terminal from Cloudron UI to access the docker container

    after running the start script, and using your ps-check command, I see a corresponding process. Additionally, running <occ notify_push:metrics> in a Cloudron terminal shows it works, all indicated stats are up-to-date and change over time.

    1 Reply Last reply
    0
    • andreasduerenA
      andreasduerenA
      andreasdueren
      App Dev
      wrote on last edited by
      #10

      I think I got Nextcloud Client Push (notify_push) working persistently with the current Cloudron Nextcloud package.

      Tested with:

      • Cloudron Nextcloud package 5.8.5
      • Nextcloud 34.0.2
      • notify_push 1.3.5

      This uses only /app/data; it does not modify read-only /app/code or /etc. I verified it across a full Cloudron app restart.

      1. Install Client Push

      Install Client Push from the Nextcloud Apps page, or run this in the Nextcloud app terminal:

      sudo -u www-data php /app/code/occ app:install notify_push || true
      sudo -u www-data php /app/code/occ app:enable notify_push
      

      2. Create the persistent daemon runner

      Run in the Nextcloud app terminal:

      mkdir -p /app/data/notify_push
      
      cat > /app/data/notify_push/runner.sh <<'EOF'
      #!/bin/bash
      
      set -u
      
      binary="/app/data/apps/notify_push/bin/x86_64/notify_push"
      config="/app/data/config/config.php"
      
      if [[ ! -x "${binary}" ]]; then
          echo "notify_push binary is missing: ${binary}" >&2
          exit 1
      fi
      
      # Apache supplies a pipe on stdin. Preserve and drain it so requests cannot block.
      exec 3<&0
      cat <&3 >/dev/null &
      reader_pid=$!
      
      "${binary}" \
          --bind 127.0.0.1 \
          --port 7867 \
          --nextcloud-url http://127.0.0.1 \
          "${config}" &
      push_pid=$!
      
      cleanup() {
          kill -TERM "${push_pid}" "${reader_pid}" 2>/dev/null || true
          wait "${push_pid}" "${reader_pid}" 2>/dev/null || true
      }
      
      trap cleanup EXIT
      trap 'exit 0' HUP INT TERM
      
      wait "${push_pid}"
      EOF
      
      chown www-data:www-data /app/data/notify_push/runner.sh
      chmod 0755 /app/data/notify_push/runner.sh
      

      The daemon binds only to loopback. Port 7867 is not exposed publicly.

      3. Add the internal callback configuration

      The daemon must contact Nextcloud directly instead of looping back through Cloudron’s public proxy:

      cat > /app/data/config/notify_push.config.php <<'EOF'
      <?php
      
      $CONFIG = [
          'trusted_domains' => [
              getenv('CLOUDRON_APP_DOMAIN'),
              '127.0.0.1',
          ],
          'trusted_proxies' => [
              getenv('CLOUDRON_PROXY_IP'),
              '127.0.0.1',
          ],
      ];
      EOF
      
      chown www-data:www-data /app/data/config/notify_push.config.php
      chmod 0640 /app/data/config/notify_push.config.php
      

      Do not add --glob-config to the daemon command. The Rust configuration parser cannot evaluate the getenv() calls in this extra PHP config file.

      4. Add the persistent Apache proxy

      First save the original configuration:

      cp -n /app/data/apache/mpm_prefork.conf \
          /app/data/apache/mpm_prefork.conf.before-notify-push
      

      Then append the integration once:

      if ! grep -Fq "BEGIN CLOUDRON NOTIFY_PUSH" /app/data/apache/mpm_prefork.conf; then
      cat >> /app/data/apache/mpm_prefork.conf <<'EOF'
      
      # BEGIN CLOUDRON NOTIFY_PUSH
      <IfModule !proxy_module>
          LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
      </IfModule>
      <IfModule !proxy_http_module>
          LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so
      </IfModule>
      <IfModule !proxy_wstunnel_module>
          LoadModule proxy_wstunnel_module /usr/lib/apache2/modules/mod_proxy_wstunnel.so
      </IfModule>
      
      ProxyPass "/push/ws" "ws://127.0.0.1:7867/ws"
      ProxyPass "/push/" "http://127.0.0.1:7867/"
      ProxyPassReverse "/push/" "http://127.0.0.1:7867/"
      
      GlobalLog "|/usr/local/bin/gosu www-data:www-data /app/data/notify_push/runner.sh" combined
      # END CLOUDRON NOTIFY_PUSH
      EOF
      fi
      
      chown www-data:www-data /app/data/apache/mpm_prefork.conf
      chmod 0644 /app/data/apache/mpm_prefork.conf
      

      GlobalLog gives Apache ownership of the daemon lifecycle. Apache starts the runner whenever the app starts and respawns it if it exits.

      5. Validate and activate Apache

      apache2ctl configtest
      

      Only continue if it reports Syntax OK:

      supervisorctl restart apache2
      

      Check that the daemon is running:

      ps -ef | grep '[n]otify_push'
      curl -i "https://${CLOUDRON_APP_DOMAIN}/push/test/cookie"
      

      The unauthenticated curl request should return HTTP 400 with Missing request header "token". That is expected and confirms the public proxy reaches the daemon.

      6. Configure Nextcloud

      sudo -u www-data php /app/code/occ \
          notify_push:setup "https://${CLOUDRON_APP_DOMAIN}/push"
      

      All checks should pass:

      ✓ redis is configured
      ✓ push server is receiving redis messages
      ✓ push server can load mount info from database
      ✓ push server can connect to the Nextcloud server
      ✓ push server is a trusted proxy
      ✓ push server is running the same version as the app
        configuration saved
      

      Run the self-test:

      sudo -u www-data php /app/code/occ notify_push:self-test
      

      7. Verify persistence

      Restart Nextcloud from the Cloudron dashboard. Once it is healthy again, reopen the terminal and run:

      sudo -u www-data php /app/code/occ notify_push:self-test
      ps -ef | grep '[n]otify_push'
      

      The saved endpoints should be:

      https://your-nextcloud-domain.example/push
      wss://your-nextcloud-domain.example/push/ws
      

      I also confirmed that both, my Hermes and the official Nextcloud sync client connected and authenticated to the WebSocket after the restart.

      Notes

      This is an instance-level workaround because the current Cloudron package has no custom supervisor hook. It follows the official notify_push architecture: a background daemon plus an Apache reverse proxy.

      Everything persistent is stored in:

      /app/data/apache/mpm_prefork.conf
      /app/data/notify_push/runner.sh
      /app/data/config/notify_push.config.php
      

      The original Apache configuration is retained at:

      /app/data/apache/mpm_prefork.conf.before-notify-push
      

      I would rerun notify_push:self-test after future Nextcloud or Cloudron package updates.

      1 Reply Last reply
      4
      • sponchS
        sponchS
        sponch
        wrote last edited by
        #11

        @andreasdueren Wow. thanks a lot! can you still recommend it?

        andreasduerenA 1 Reply Last reply
        0
        • sponchS sponch

          @andreasdueren Wow. thanks a lot! can you still recommend it?

          andreasduerenA
          andreasduerenA
          andreasdueren
          App Dev
          wrote last edited by
          #12

          Yes, still recommend it with one caveat: the setup survives Cloudron package updates fine, but a Nextcloud major upgrade can silently take it out. Mine broke going from 34 to 35.

          After the upgrade notify_push was gone from occ app:list, no process, nothing on port 7867, but oc_appconfig still held base_endpoint with enabled: "no". Config intact in the database, app code gone from disk. For the record, it was not the package overwriting anything: start.sh only copies mpm_prefork.conf when it is absent, and notify_push is not in apps_template, so both persistent hooks from my guide are genuinely durable. A second instance on the same Nextcloud version kept running throughout.

          GlobalLog already respawns the runner, so process death was never the issue. A disabled app or missing binary was. I moved that check into runner.sh before the daemon launches: if the binary is not executable or occ app:list shows no version, it runs app:install (falling back to app:update) then app:enable. If the binary is still missing it sleeps 300s and exits, which matters because Apache restarts the pipe target immediately and a fast-failing runner turns into a hot loop. I tested it by deleting the app directory outright, and Apache had it reinstalled and serving again three seconds later, confirmed across a full app restart.

          One pitfall: right after a self-heal reinstall, notify_push:self-test may report push server can't connect to the Nextcloud server / Client error: 404 Not Found. That is a stale route cache, not a broken setup. supervisorctl restart apache2 clears it. Still worth running occ notify_push:self-test after every Nextcloud upgrade, since the runner deliberately cannot paper over a release with no compatible notify_push at all.

          1 Reply Last reply
          0
          • andreasduerenA
            andreasduerenA
            andreasdueren
            App Dev
            wrote last edited by andreasdueren
            #13

            Here's the updated guide. Changes: hardened self-healing runner in step 2, new step 8 for failure injection, corrected facts about what actually survives updates, and refreshed versions.

            1. Install Client Push

            Install Client Push from the Nextcloud Apps page, or run this in the Nextcloud app terminal:

            sudo -u www-data php /app/code/occ app:install notify_push || true
            sudo -u www-data php /app/code/occ app:enable notify_push
            

            2. Create the persistent daemon runner

            Run in the Nextcloud app terminal:

            mkdir -p /app/data/notify_push
            
            cat > /app/data/notify_push/runner.sh <<'EOF'
            #!/bin/bash
            # Self-healing notify_push runner, started and respawned by Apache GlobalLog.
            # Survives Nextcloud major upgrades that disable or remove the app.
            
            set -u
            
            binary="/app/data/apps/notify_push/bin/x86_64/notify_push"
            config="/app/data/config/config.php"
            occ="php /app/code/occ"
            log="/app/data/notify_push/runner.log"
            
            say() { echo "$(date -u +%FT%TZ) $*" >> "${log}"; }
            
            # Apache supplies a pipe on stdin. Preserve and drain it so requests cannot block.
            exec 3<&0
            cat <&3 >/dev/null &
            reader_pid=$!
            
            cleanup() {
                kill -TERM ${push_pid:-} "${reader_pid}" 2>/dev/null || true
                wait ${push_pid:-} "${reader_pid}" 2>/dev/null || true
            }
            
            trap cleanup EXIT
            trap 'exit 0' HUP INT TERM
            
            # A major Nextcloud upgrade can mark the app incompatible, disable it, and
            # leave the code directory gone while the DB config survives. Repair that here.
            app_ver="$(${occ} app:list --output=json 2>/dev/null \
                | grep -o '"notify_push":"[^"]*"' | cut -d'"' -f4 || true)"
            
            if [[ ! -x "${binary}" || -z "${app_ver}" ]]; then
                say "binary or app missing (app_ver='${app_ver}'); attempting repair"
                ${occ} app:install notify_push >>"${log}" 2>&1 \
                    || ${occ} app:update notify_push >>"${log}" 2>&1 || true
                ${occ} app:enable notify_push >>"${log}" 2>&1 || true
            fi
            
            if [[ ! -x "${binary}" ]]; then
                say "repair failed, binary still missing; backing off 300s"
                sleep 300
                exit 1
            fi
            
            say "starting notify_push"
            "${binary}" \
                --bind 127.0.0.1 \
                --port 7867 \
                --nextcloud-url http://127.0.0.1 \
                "${config}" &
            push_pid=$!
            
            wait "${push_pid}"
            rc=$?
            say "notify_push exited rc=${rc}; backing off 10s"
            sleep 10
            exit "${rc}"
            EOF
            
            chown www-data:www-data /app/data/notify_push/runner.sh
            chmod 0755 /app/data/notify_push/runner.sh
            touch /app/data/notify_push/runner.log
            chown www-data:www-data /app/data/notify_push/runner.log
            bash -n /app/data/notify_push/runner.sh && echo "syntax OK"
            

            The daemon binds only to loopback. Port 7867 is not exposed publicly.

            Both sleep calls are deliberate. Apache respawns the pipe target immediately, so a runner that fails fast becomes a hot respawn loop. The runner executes under gosu www-data, so occ needs no sudo here.

            3. Add the internal callback configuration

            The daemon must contact Nextcloud directly instead of looping back through Cloudron's public proxy:

            cat > /app/data/config/notify_push.config.php <<'EOF'
            <?php
            
            $CONFIG = [
                'trusted_domains' => [
                    getenv('CLOUDRON_APP_DOMAIN'),
                    '127.0.0.1',
                ],
                'trusted_proxies' => [
                    getenv('CLOUDRON_PROXY_IP'),
                    '127.0.0.1',
                ],
            ];
            EOF
            
            chown www-data:www-data /app/data/config/notify_push.config.php
            chmod 0640 /app/data/config/notify_push.config.php
            

            Do not add --glob-config to the daemon command. The Rust configuration parser cannot evaluate the getenv() calls in this extra PHP config file.

            4. Add the persistent Apache proxy

            First save the original configuration:

            cp -n /app/data/apache/mpm_prefork.conf \
                /app/data/apache/mpm_prefork.conf.before-notify-push
            

            Then append the integration once:

            if ! grep -Fq "BEGIN CLOUDRON NOTIFY_PUSH" /app/data/apache/mpm_prefork.conf; then
            cat >> /app/data/apache/mpm_prefork.conf <<'EOF'
            
            # BEGIN CLOUDRON NOTIFY_PUSH
            <IfModule !proxy_module>
                LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
            </IfModule>
            <IfModule !proxy_http_module>
                LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so
            </IfModule>
            <IfModule !proxy_wstunnel_module>
                LoadModule proxy_wstunnel_module /usr/lib/apache2/modules/mod_proxy_wstunnel.so
            </IfModule>
            
            ProxyPass "/push/ws" "ws://127.0.0.1:7867/ws"
            ProxyPass "/push/" "http://127.0.0.1:7867/"
            ProxyPassReverse "/push/" "http://127.0.0.1:7867/"
            
            GlobalLog "|/usr/local/bin/gosu www-data:www-data /app/data/notify_push/runner.sh" combined
            # END CLOUDRON NOTIFY_PUSH
            EOF
            fi
            
            chown www-data:www-data /app/data/apache/mpm_prefork.conf
            chmod 0644 /app/data/apache/mpm_prefork.conf
            

            GlobalLog gives Apache ownership of the daemon lifecycle. Apache starts the runner whenever the app starts and respawns it if it exits.

            This file is safe to edit. start.sh only copies the package default when the file is absent:

            [[ ! -f /app/data/apache/mpm_prefork.conf ]] && cp /app/pkg/mpm_prefork.conf /app/data/apache/mpm_prefork.conf
            

            If you later tune MPM settings here, keep the NOTIFY_PUSH block.

            5. Validate and activate Apache

            apache2ctl configtest
            

            Only continue if it reports Syntax OK:

            supervisorctl restart apache2
            

            Check that the daemon is running:

            ps -ef | grep '[n]otify_push'
            curl -i "https://${CLOUDRON_APP_DOMAIN}/push/test/cookie"
            

            The unauthenticated curl request should return HTTP 400 with Missing request header "token". That is expected and confirms the public proxy reaches the daemon.

            Raise MaxRequestWorkers

            Important, courtesy of @sponch below: because the WebSocket is proxied through Apache, under prefork every connected client holds one worker for the whole lifetime of its push connection. The Nextcloud package default of MaxRequestWorkers 15 means roughly 15 connected clients can exhaust the pool and leave Nextcloud unresponsive, with no workers left for page loads, WebDAV or Talk.

            Check and raise it in the same file:

            grep -E "MaxRequestWorkers" /app/data/apache/mpm_prefork.conf
            

            Count one slot per device, not per user, since a phone and a laptop each hold their own connection. Add generous headroom on top for ordinary requests. Verify with apache2ctl configtest before restarting.

            Do not simply copy a large number. Each prefork worker can grow to PHP's memory_limit, so the safe ceiling depends on your RAM and on any Cloudron memory limit for the app. Measure the marginal cost per worker rather than guessing:

            for p in $(ps -eo pid,comm | awk '$2=="apache2"{print $1}'); do
                awk '/^Pss:/{s+=$2} END{print s+0}' /proc/$p/smaps_rollup 2>/dev/null
            done | awk '{s+=$1; n++} END{printf "workers=%d avg PSS=%.1f MB\n", n, s/n/1024}'
            

            Note that prefork also needs ServerLimit raised if you go above 256.

            6. Configure Nextcloud

            sudo -u www-data php /app/code/occ \
                notify_push:setup "https://${CLOUDRON_APP_DOMAIN}/push"
            

            All checks should pass:

            ✓ redis is configured
            ✓ push server is receiving redis messages
            ✓ push server can load mount info from database
            ✓ push server can connect to the Nextcloud server
            ✓ push server is a trusted proxy
            ✓ push server is running the same version as the app
              configuration saved
            

            Run the self-test:

            sudo -u www-data php /app/code/occ notify_push:self-test
            

            7. Verify persistence

            Restart Nextcloud from the Cloudron dashboard. Once it is healthy again, reopen the terminal and run:

            sudo -u www-data php /app/code/occ notify_push:self-test
            ps -ef | grep '[n]otify_push'
            

            The saved endpoints should be:

            https://your-nextcloud-domain.example/push
            wss://your-nextcloud-domain.example/push/ws
            

            Note that a passing self-test alone does not prove persistence. The process must still be present after the restart, with new PIDs.

            8. Verify self-healing

            Simulate what a bad upgrade does, then confirm recovery:

            mv /app/data/apps/notify_push /app/data/apps/.notify_push.bak
            supervisorctl restart apache2
            sleep 45
            
            ls -la /app/data/apps/notify_push/bin/x86_64/notify_push
            ps -ef | grep '[n]otify_push'
            cat /app/data/notify_push/runner.log
            

            Expected log output:

            binary or app missing (app_ver=''); attempting repair
            notify_push 1.4.1 installed
            notify_push enabled
            starting notify_push
            

            Then clean up the injected directory:

            rm -rf /app/data/apps/.notify_push.bak
            

            Right after a self-heal reinstall, notify_push:self-test may report push server can't connect to the Nextcloud server with Client error: 404 Not Found. That is a stale Nextcloud route cache, not a broken setup; loopback status.php still returns 200. Run supervisorctl restart apache2 and re-test.

            Notes

            This is an instance-level workaround because the current Cloudron package has no custom supervisor hook. It follows the official notify_push architecture: a background daemon plus an Apache reverse proxy.

            Everything persistent is stored in:

            /app/data/apache/mpm_prefork.conf
            /app/data/notify_push/runner.sh
            /app/data/config/notify_push.config.php
            

            The original Apache configuration is retained at:

            /app/data/apache/mpm_prefork.conf.before-notify-push
            

            For what it is worth, the Cloudron package itself does not remove any of this. notify_push is not in /app/pkg/apps_template, and the update loop only replaces template apps. The failure mode worth guarding against is the Nextcloud app being disabled or removed during a major Nextcloud upgrade, which is what step 2 now handles. I would still rerun notify_push:self-test after future Nextcloud or Cloudron package updates, and check runner.log if push goes quiet.

            1 Reply Last reply
            3
            • sponchS
              sponchS
              sponch
              wrote last edited by
              #14

              Hi @andreasdueren this is great and works perfect right now. Thanks a lot for your work!!
              Do you see any chance this being integrated in the official package?
              Bildschirmfoto 2026-10-08 um 07.39.51.png

              andreasduerenA 1 Reply Last reply
              3
              • sponchS sponch

                Hi @andreasdueren this is great and works perfect right now. Thanks a lot for your work!!
                Do you see any chance this being integrated in the official package?
                Bildschirmfoto 2026-10-08 um 07.39.51.png

                andreasduerenA
                andreasduerenA
                andreasdueren
                App Dev
                wrote last edited by
                #15

                @sponch No idea, I'm not maintaining it 😄 Gotta ping @girish

                1 Reply Last reply
                2
                • girishG
                  girishG
                  girish
                  Staff
                  wrote last edited by
                  #16

                  We won't integrate plugins into the nextcloud package, if this is the question. Unfortunately, nextcloud is hard to maintain as it is with so many plugins.

                  1 Reply Last reply
                  3
                  • sponchS
                    sponchS
                    sponch
                    wrote last edited by
                    #17

                    @andreasdueren

                    After some digging, I found out that every connected Nextcloud client (desktop or phone) keeps one apache process busy for the push connection.
                    By default the app seems to allow only 15 of them (MaxRequestWorkers 15) in /app/data/apache/mpm_prefork.conf). Once about 15 clients were online NC was unresponsive.

                    I changed that line in /app/data/apache/mpm_prefork.conf to
                    "MaxRequestWorkers 150" and the problem was gone.

                    Just in case anyone else running over that. (maybe you can add it to your guide above).

                    andreasduerenA 1 Reply Last reply
                    3
                    • sponchS sponch

                      @andreasdueren

                      After some digging, I found out that every connected Nextcloud client (desktop or phone) keeps one apache process busy for the push connection.
                      By default the app seems to allow only 15 of them (MaxRequestWorkers 15) in /app/data/apache/mpm_prefork.conf). Once about 15 clients were online NC was unresponsive.

                      I changed that line in /app/data/apache/mpm_prefork.conf to
                      "MaxRequestWorkers 150" and the problem was gone.

                      Just in case anyone else running over that. (maybe you can add it to your guide above).

                      andreasduerenA
                      andreasduerenA
                      andreasdueren
                      App Dev
                      wrote last edited by
                      #18

                      @sponch Yes, good point. I had raised the limit a while ago for different reason. Will update guide though with a hint to this.

                      1 Reply Last reply
                      2

                      Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                      Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                      With your input, this post could be even better 💗

                      Register Login
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Bookmarks
                      • Search