Install Nextcloud on Debian 12

Nextcloud is a self-hosted, open-source platform for file hosting and sharing, similar to Dropbox or Google Drive. It allows users to store, sync, and share files, as well as collaborate on documents, calendars, and more, all while maintaining control over their data.

Install packages

sudo aptitude install \
    caddy \
    php php-fpm php-mysql php-common php-gd php-xml php-mbstring php-zip php-curl php-intl \
    mariadb-server

.. note::

   ``php-intl`` is necessary for creating sessions in Nextcloud Talk.

Configure Caddy

sudo systemctl start caddy
sudo systemctl enable caddy
sudo systemctl status caddy
sudo nvim /etc/caddy/Caddyfile.d/foo.com.caddyfile
cloud.foo.com {
    root * /usr/share/caddy/cloudfoo
    php_fastcgi unix//run/php/php8.2-fpm.sock
    file_server

    log {
        output file /var/log/caddy/foo.com-access.log
    }
}
sudo systemctl restart caddy

Configure PHP

php --version
sudo sed -i 's/www-data/caddy/g' /etc/php/8.2/fpm/pool.d/www.conf

Uncomment in sudo vi /etc/php/8.2/fpm/pool.d/www.conf

env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
sudo systemctl restart php8.2-fpm

Database

sudo mysql_secure_installation
sudo mysql -u root -p

Create a new database and user for Nextcloud:

CREATE DATABASE cloudfoo;
GRANT ALL ON cloudfoo.* TO 'cloudfoo'@'localhost' IDENTIFIED BY '<PLACEHOLDER_DB_PASSWORD>';
FLUSH PRIVILEGES;
EXIT;

Nextcloud

mkdir ~/Downloads
cd ~/Downloads
wget https://download.nextcloud.com/server/releases/latest.tar.bz2
tar xvf latest.tar.bz2
sudo mv nextcloud /usr/share/caddy/cloudfoo
sudo mkdir /usr/share/caddy/cloudfoo/data
sudo chown -R caddy:caddy /usr/share/caddy/cloudfoo/
sudo chmod -R 755 /usr/share/caddy/cloudfoo/
# Use this as the secret:
openssl rand -hex 32

Add 'trusted_proxies' => ['cloud.foo.com'], to sudo -u caddy vi /usr/share/caddy/cloudfoo/config/config.php.

Set memory_limit = 512M, post_max_size = 256M in sudo vi /etc/php/8.2/fpm/php.ini, and restart php-fpm:

sudo systemctl restart php8.2-fpm.service

Point browser to https://cloud.foo.com.

Video call

sudo aptitude install coturn
sudo ufw allow 3478/tcp
sudo ufw allow 3478/udp

sudo vi /etc/turnserver.conf:

listening-port=3478
fingerprint
lt-cred-mech
use-auth-secret
static-auth-secret=<PLACEHOLDER_AUTH_SECRET>
server-name=cloud.foo.com
total-quota=100
stale-nonce=600
syslog
no-multicast-peers
no-rfc5780
no-stun-backward-compatibility
response-origin-only-with-rfc5780
sudo systemctl restart coturn

Go to Admin Panel -> Talk

  • STUN: stun.nextcloud.com:443

  • TURN Servers

    • turn: only

    • TURN server URL: cloud.foo.com:3478

    • TURN server secret: <PLACEHOLDER_AUTH_SECRET>

    • UDP and TCP

Trouble Shooting

"Your remote address was identified as "xx.xxx.xxx.xxx" and is throttled at the moment by 6400ms."

  • Activate app "Brute-force settings".

  • Go to "Security" -> "Add new whitelist", add the IP address.

"The .htaccess file is not working"

Add this to sudo vi /etc/caddy/Caddyfile.d/foo.com.caddyfile:

cloud.foo.com {
    root * /usr/share/caddy/cloudfoo
    php_fastcgi unix//run/php/php8.2-fpm.sock

    log {
        output file /var/log/caddy/foo.com-access.log
    }

    # All of the following is from:
    # https://caddy.community/t/caddy-v2-configuration-nextcloud-docker-php-fpm-with-rules-from-htaccess/20662

    # Rules here are all from .htaccess
    redir /.well-known/carddav /remote.php/dav 301
    redir /.well-known/caldav /remote.php/dav 301
    redir /.well-known/* /index.php{uri} 301 # Nextcloud front-controller handles routes to /.well-known
    redir /remote/* /remote.php{uri} 301

    # Secure headers, all from .htaccess except Permissions-Policy, STS and X-Powered-By
    header {
        Strict-Transport-Security max-age=31536000
        Permissions-Policy interest-cohort=()
        X-Content-Type-Options nosniff
        X-Frame-Options SAMEORIGIN
        Referrer-Policy no-referrer
        X-XSS-Protection "1; mode=block"
        X-Permitted-Cross-Domain-Policies none
        X-Robots-Tag "noindex, nofollow"
        -X-Powered-By
    }

    # Uncomment this block if you use the high speed files backend: https://github.com/nextcloud/notify_push
    #handle_path /push/* {
    #    reverse_proxy unix//run/notify_push/notify_push.sock # I love Unix sockets, but you can do :7867 also
    #}

    # Uncomment this block if you use onlyoffice: https://github.com/nextcloud/all-in-one/blob/main/Containers/apache/Caddyfile
    #handle_path /onlyoffice/* {
    #    reverse_proxy {$ONLYOFFICE_IP}:{$ONLYOFFICE_PORT} {
    #        header_up X-Forwarded-Host {host}/onlyoffice
    #    }
    #}

    # PHP block
    # As I said before, i'm a fan of Unix sockets, so I use them as much as I can. But you can do :9000 also for TCP.
    php_fastcgi unix//run/nextcloud/nextcloud.sock {
        root /var/www/html # This is needed because inside the container the root directory is different from the one I put in the "root" directive of this Caddyfile. If you don't change this, php-fpm will not be able to find the files to process.
        env front_controller_active true # Enable pretty urls
        env modHeadersAvailable true # Avoid sending the security headers twice
    }

    # From .htaccess, deny access to sensible files and directories
    @forbidden {
        path /build/* /tests/* /config/* /lib/* /3rdparty/* /templates/* /data/*
        path /.* /autotest* /occ* /issue* /indie* /db_* /console*
        not path /.well-known/*
    }
    error @forbidden 404

    # From .htaccess, set cache for versioned static files (cache-busting)
    @immutable {
        path *.css *.js *.mjs *.svg *.gif *.png *.jpg *.ico *.wasm *.tflite
        query v=*
    }
    header @immutable Cache-Control "max-age=15778463, immutable"

    # From .htaccess, set cache for normal static files
    @static {
        path *.css *.js *.mjs *.svg *.gif *.png *.jpg *.ico *.wasm *.tflite
        not query v=*
    }
    header @static Cache-Control "max-age=15778463"

    # From .htaccess, cache fonts for 1 week
    @woff2 path *.woff2
    header @woff2 Cache-Control "max-age=604800"

    file_server
}

Resources