Passa al contenuto principale

Installing NextCloud

Installing NextCloud in the most traditional way, using system packages, and fixing configuration files. We will use NGINX and PosgreSQL, so that we get some familiarity with them too, although it can be installed with Apache2 and MariaDB as well. Most of the web applications can use both MariaDB and PostgreSQL as a DB, but some of them can use only one. NGINX and Apache2 can be use for any web application (either one or the other, usually not both at the same time).

1. Install Web Stack

1.1 Install NGINX

First let's stop and disable apache2, because nginx needs to use the same ports (80 and 443), so they can't run at the same time:

systemctl stop apache2
systemctl status apache2
systemctl disable apache2
systemctl status apache2
systemctl mask apache2
systemctl status apache2

mv /var/www/html/index{,-apache2}.html

Now let's install nginx:

apt install nginx
nginx -v
systemctl status nginx

To test it, open in browser http://188.245.242.143/ or http://www.user1.fs.al

1.2 Test PHP

We have installed PHP previously, let's test that it works with NGINX:

  1. Edit /etc/nginx/sites-enabled/default and uncomment the PHP configuration:

    location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php-fpm.sock;
    }
  2. Reload nginx configuration:

    nginx -t
    systemctl reload nginx
  3. Create a test file info.php on the root of the webserver:

    ls /var/www/html/
    echo "<?php phpinfo(); ?>" > /var/www/html/info.php
    cat /var/www/html/info.php
  4. Try in browser http://www.user1.fs.al/info.php

  5. Once you confirm that it works, remove the file info.php (for security reasons):

    rm /var/www/html/info.php

1.3 Enable HTTPS

  1. Edit /etc/nginx/sites-enabled/default and uncomment these lines:

    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    include snippets/snakeoil.conf;

    We have already installed the package ssl-cert, which generates the self-signed certificate ssl-cert-snakeoil.

    nano /etc/nginx/snippets/snakeoil.conf
  2. Reload nginx configuration:

    nginx -t
    systemctl reload nginx
  3. Open in browser HTTPS://www.user1.fs.al/

1.4 Setup LetsEncrypt

  1. Create the config file /etc/nginx/snippets/letsencrypt.conf:

    cat <<'_EOF_' > /etc/nginx/snippets/letsencrypt.conf
    location ^~ /.well-known/acme-challenge/ {
    allow all;
    default_type "text/plain";
    root /var/www;
    }

    location = /.well-known/acme-challenge/ {
    return 404;
    }
    _EOF_
  2. Include it at /etc/nginx/sites-enabled/default:

    server {
    # . . . . . . . . . .
    include snippets/snakeoil.conf;
    include snippets/letsencrypt.conf;
    # . . . . . . . . . .
    }
  3. Reload nginx:

    nginx -t
    systemctl reload nginx
  4. Test getting a certificate with certbot --dry-run:

    certbot certonly \
    --webroot -w /var/www \
    -d nc1.user1.fs.al \
    --dry-run
Removing comments

We can remove the comments and the empty lines from the config file like this:

cd /etc/nginx/
ls sites-available/
cp sites-available/default{,.bak}
ls sites-available/

grep '#' sites-available/default
sed sites-available/default -e '/#/ d'
sed sites-available/default -e '/#/ d' -e '/^$/ d'
sed -i sites-available/default -e '/#/d' -e '/^$/d'

nginx -t
systemctl reload nginx

After removing the comments (and changing the order of some lines), the config file should look like this:

server {
server_name _;
listen 80 default_server;
listen [::]:80 default_server;

listen 443 ssl default_server;
listen [::]:443 ssl default_server;
include snippets/snakeoil.conf;

include snippets/letsencrypt.conf;

root /var/www/html;
index index.html index.htm index.nginx-debian.html;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
}

1.5 Install PostgreSQL

PostgreSQL uses a different port (5432) from MariaDB (3306), so they can actually run at the same time. But let's stop MariaDB anyway, since we don't need it right now:

systemctl stop mariadb
systemctl disable mariadb
systemctl mask mariadb
systemctl status mariadb

Install PostgreSQL:

apt install postgresql postgresql-contrib
systemctl status postgresql
pg_lsclusters
pg_isready
Try some psql commands
su -l postgres
pwd
whoami
psql
\l
\l postgres
\x
\l postgres
select * from pg_user;
\l
\?
\q

2. Install NextCloud

2.1 Install PHP modules

PHP is already installed, but let's make sure that we also install some PHP modules that are needed by NextCloud or its plugins:

# packages needed by postgres and nginx
apt install \
php-pgsql \
php8.2-fpm
systemctl status php8.2-fpm
apt install \
php-common \
php-dev \
php-curl \
php-gd \
php-mbstring \
php-xml \
php-zip \
php-bz2 \
php-intl \
php-ldap \
php-imap \
php-bcmath \
php-gmp \
php-json \
php-pear \
php-soap \
php-apcu \
php-imagick \
libmagickcore-dev \
php-redis \
php-memcached

2.2 Create a Database

  1. Create a database:

    su -l postgres -c psql
    CREATE DATABASE nc1db TEMPLATE template0 ENCODING 'UTF8';
    \x
    \l nc1
  2. Create a user:

    CREATE USER nc1user WITH PASSWORD 'nc1pass' CREATEDB;
    select * from pg_user;
  3. Set the user as the owner of the database and grant all the privileges to it:

    ALTER DATABASE nc1db OWNER TO nc1user;
    GRANT ALL PRIVILEGES ON DATABASE nc1db TO nc1user;
    GRANT ALL PRIVILEGES ON SCHEMA public TO nc1user;
    \du

    \q

2.3 Get NC Code

  1. Download NC:

    wget https://download.nextcloud.com/server/releases/latest.tar.bz2
    tar xjf latest.tar.bz2
    rm latest.tar.bz2

    mv nextcloud/ /var/www/nc1
    ls /var/www/
  2. Fix ownership:

    chown www-data:www-data -R /var/www/nc1
    ls -al /var/www/nc1/

2.4 Create a Virtual Host

  1. Create the file /etc/nginx/sites-available/nc1 with a content like this:

    /etc/nginx/sites-available/nc1
    upstream php-handler {
    #server 127.0.0.1:9000;
    server unix:/run/php/php8.2-fpm.sock;
    }

    # Set the `immutable` cache control options only for assets with a cache busting `v` argument
    map $arg_v $asset_immutable {
    "" "";
    default ", immutable";
    }

    server {
    listen 80;
    listen [::]:80;
    server_name nc1.user1.fs.al;

    # Prevent nginx HTTP Server Detection
    server_tokens off;

    # Handle LetsEncrypt challenges
    include snippets/letsencrypt.conf;

    location ^~ / {
    # Redirect HTTP to HTTPS
    return 301 https://$server_name$request_uri;
    }
    }

    server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name nc1.user1.fs.al;

    # Path to the root of your installation
    root /var/www/nc1;

    # Use Mozilla's guidelines for SSL/TLS settings
    # https://mozilla.github.io/server-side-tls/ssl-config-generator/
    ssl_certificate /etc/letsencrypt/live/nc1.user1.fs.al/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/nc1.user1.fs.al/privkey.pem;

    # Prevent nginx HTTP Server Detection
    server_tokens off;

    # HSTS settings
    # WARNING: Only add the preload option once you read about
    # the consequences in https://hstspreload.org/. This option
    # will add the domain to a hardcoded list that is shipped
    # in all major browsers and getting removed from this list
    # could take several months.
    #add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always;

    # set max upload size and increase upload timeout:
    client_max_body_size 512M;
    client_body_timeout 300s;
    fastcgi_buffers 64 4K;

    # Enable gzip but do not remove ETag headers
    gzip on;
    gzip_vary on;
    gzip_comp_level 4;
    gzip_min_length 256;
    gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
    gzip_types application/atom+xml text/javascript application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

    # Pagespeed is not supported by Nextcloud, so if your server is built
    # with the `ngx_pagespeed` module, uncomment this line to disable it.
    #pagespeed off;

    # The settings allows you to optimize the HTTP2 bandwidth.
    # See https://blog.cloudflare.com/delivering-http-2-upload-speed-improvements/
    # for tuning hints
    client_body_buffer_size 512k;

    # HTTP response headers borrowed from Nextcloud `.htaccess`
    add_header Referrer-Policy "no-referrer" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Permitted-Cross-Domain-Policies "none" always;
    add_header X-Robots-Tag "noindex, nofollow" always;
    add_header X-XSS-Protection "1; mode=block" always;

    # Remove X-Powered-By, which is an information leak
    fastcgi_hide_header X-Powered-By;

    # Set .mjs and .wasm MIME types
    # Either include it in the default mime.types list
    # and include that list explicitly or add the file extension
    # only for Nextcloud like below:
    include mime.types;
    types {
    text/javascript mjs;
    # application/wasm wasm;
    }

    # Specify how to handle directories -- specifying `/index.php$request_uri`
    # here as the fallback means that Nginx always exhibits the desired behaviour
    # when a client requests a path that corresponds to a directory that exists
    # on the server. In particular, if that directory contains an index.php file,
    # that file is correctly served; if it doesn't, then the request is passed to
    # the front-end controller. This consistent behaviour means that we don't need
    # to specify custom rules for certain paths (e.g. images and other assets,
    # `/updater`, `/ocs-provider`), and thus
    # `try_files $uri $uri/ /index.php$request_uri`
    # always provides the desired behaviour.
    index index.php index.html /index.php$request_uri;

    # Rule borrowed from `.htaccess` to handle Microsoft DAV clients
    location = / {
    if ( $http_user_agent ~ ^DavClnt ) {
    return 302 /remote.php/webdav/$is_args$args;
    }
    }

    location = /robots.txt {
    allow all;
    log_not_found off;
    access_log off;
    }

    # Make a regex exception for `/.well-known` so that clients can still
    # access it despite the existence of the regex rule
    # `location ~ /(\.|autotest|...)` which would otherwise handle requests
    # for `/.well-known`.
    location ^~ /.well-known {
    # The rules in this block are an adaptation of the rules
    # in `.htaccess` that concern `/.well-known`.

    location = /.well-known/carddav { return 301 /remote.php/dav/; }
    location = /.well-known/caldav { return 301 /remote.php/dav/; }

    location /.well-known/acme-challenge { try_files $uri $uri/ =404; }
    location /.well-known/pki-validation { try_files $uri $uri/ =404; }

    # Let Nextcloud's API for `/.well-known` URIs handle all other
    # requests by passing them to the front-end controller.
    return 301 /index.php$request_uri;
    }

    # Rules borrowed from `.htaccess` to hide certain paths from clients
    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; }
    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; }

    # Ensure this block, which passes PHP files to the PHP process, is above the blocks
    # which handle static assets (as seen below). If this block is not declared first,
    # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
    # to the URI, resulting in a HTTP 500 error response.
    location ~ \.php(?:$|/) {
    # Required for legacy support
    rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|ocs-provider\/.+|.+\/richdocumentscode(_arm64)?\/proxy) /index.php$request_uri;

    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    set $path_info $fastcgi_path_info;

    try_files $fastcgi_script_name =404;

    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $path_info;
    fastcgi_param HTTPS on;

    fastcgi_param modHeadersAvailable true; # Avoid sending the security headers twice
    fastcgi_param front_controller_active true; # Enable pretty urls
    fastcgi_pass php-handler;

    fastcgi_intercept_errors on;
    fastcgi_request_buffering off;

    fastcgi_max_temp_file_size 0;
    }

    # Serve static files
    location ~ \.(?:css|js|mjs|svg|gif|ico|jpg|png|webp|wasm|tflite|map|ogg|flac)$ {
    try_files $uri /index.php$request_uri;
    # HTTP response headers borrowed from Nextcloud `.htaccess`
    add_header Cache-Control "public, max-age=15778463$asset_immutable";
    add_header Referrer-Policy "no-referrer" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Permitted-Cross-Domain-Policies "none" always;
    add_header X-Robots-Tag "noindex, nofollow" always;
    add_header X-XSS-Protection "1; mode=block" always;
    access_log off; # Optional: Don't log access to assets
    }

    location ~ \.(otf|woff2?)$ {
    try_files $uri /index.php$request_uri;
    expires 7d; # Cache-Control policy borrowed from `.htaccess`
    access_log off; # Optional: Don't log access to assets
    }

    # Rule borrowed from `.htaccess`
    location /remote {
    return 301 /remote.php$request_uri;
    }

    location / {
    try_files $uri $uri/ /index.php$request_uri;
    }
    }

    For more details see: https://docs.nextcloud.com/server/stable/admin_manual/installation/nginx.html

    Download

    Download nc1-config.nginx

    wget https://linux-cli.fs.al/apps/part2/nc1-config.nginx
    mv nc1-config.nginx /etc/nginx/sites-available/nc1
    nano /etc/nginx/sites-available/nc1
  2. Link to it from sites-enabled/:

    ln -s ../sites-available/nc1 /etc/nginx/sites-enabled/nc1
    ls -l /etc/nginx/sites-enabled/

    nginx -t

    We don't have yet an SSL cert.

  3. Get an SSL cert from LetsEncrypt:

    certbot certonly \
    --webroot -w /var/www \
    -d nc1.user1.fs.al \
    --dry-run

    certbot certonly \
    --webroot -w /var/www \
    -d nc1.user1.fs.al \
    -m dashohoxha@gmail.com \
    --agree-tos

    certbot certificates
  4. Reload the nginx config:

    nginx -t
    systemctl reload nginx

2.4 Run wizard

Open in browser https://nc1.user1.fs.al and give the required details about the admin account and database settings.

After the installation is finished, explore a little bit. Try to install another app. Create another user.

3. Improvements

If we check the overview of the admin settings, we will notice that it is reporting some errors and warnings that need to be fixed: https://nc1.user1.fs.al/settings/admin/overview

Let's start by trying to fix these, and then we may also make some other improvements.

3.1 Fix PHP memory limit

Edit /etc/php/8.2/fpm/php.ini and set memory_limit at least 512M:

; Maximum amount of memory a script may consume
; https://php.net/memory-limit
memory_limit = 512M

Then reload the service php8.2-fpm and check that the error is not reported anymore:

systemctl reload php8.2-fpm

3.2 Create an alias for occ

It is a useful command for managing NextCloud from the terminal:

sudo -u www-data php /var/www/nc1/occ

But it is a bit awkward to run it like this. Let's create an alias for it:

alias occ='sudo -u www-data php /var/www/nc1/occ'
echo "alias occ='sudo -u www-data php /var/www/nc1/occ'" >> ~/.bashrc_custom
nano ~/.bashrc_custom

occ
occ | less
occ --ansi | less -r
Fix also /etc/hosts
note

Modify also /etc/hosts and make sure that it contains this line:

127.0.1.1  mycloud

This will avoid a warning by sudo. Here, mycloud is the hostname (the result of the command hostname).

suggerimento

Add also lines like these to /etc/hosts:

127.0.0.1  nc1.user1.fs.al
127.0.0.1 wp1.user1.fs.al
127.0.0.1 wp1.user1.fs.al

This way the apps won’t have to query the public DNS, which may improve the overall stability.

3.3 Corrections with occ

Set maintenance_window_start:

occ config:system:get maintenance_window_start    # get
occ config:system:set maintenance_window_start --type=integer --value=1
occ config:system:get maintenance_window_start
note

This command will actually add a new setting at the config file /var/www/nc1/config/config.php:

cd /var/www/nc1/
nano config/config.php

Make some more corrections with occ:

occ maintenance:repair --include-expensive
occ db:add-missing-indices

occ config:system:set default_phone_region --value=AL

3.4 Running cron jobs

On the page https://nc1.user1.fs.al/settings/admin we see that the recommended way for running background jobs is cron. We need to call periodically php -f /var/www/nc1/cron.php, as the user www-data.

One way to do it is by using cron and crontab:

  1. Edit the cron table of user www-data:

    crontab -u www-data -e
  2. Append this line:

    */5  *  *  *  * php -f /var/www/nc1/cron.php

However, let's do it instead with systemd:

  1. Create the file /etc/systemd/system/nc1cron.service:

    [Unit]
    Description=nc1 cron.php job

    [Service]
    User=www-data
    ExecCondition=php -f /var/www/nc1/occ status -e
    ExecStart=/usr/bin/php -f /var/www/nc1/cron.php
    KillMode=process
  2. Create the file /etc/systemd/system/nc1cron.timer:

    [Unit]
    Description=Run nc1cron.service every 5 minutes

    [Timer]
    OnBootSec=5min
    OnUnitActiveSec=5min
    Unit=nc1cron.service

    [Install]
    WantedBy=timers.target
  3. Enable and start the timer:

    systemctl enable --now nc1cron.timer
    systemctl status nc1cron

Reload the page https://nc1.user1.fs.al/settings/admin and verify that NC now is using cron for the background jobs.

3.5 Fix PHP-FPM configuration

  1. Edit /etc/php/8.2/fpm/pool.d/www.conf and uncomment these lines (near the end):

    env[PATH] = /usr/local/bin:/usr/bin:/bin
    env[TMP] = /tmp
  2. Restart php8.2-fpm:

    systemctl restart php8.2-fpm

3.6 Enable OPCache

The PHP OPcache improves the performance of PHP applications by caching precompiled bytecode.

Edit /etc/php/8.2/fpm/php.ini and uncomment/modify these lines:

[PHP]
zend_extension=opcache

[opcache]
opcache.enable=1
opcache.interned_strings_buffer=64
opcache.revalidate_freq=60

Then restart php8.2-fpm:

systemctl restart php8.2-fpm

3.7 Change max upload size

  1. Edit /etc/nginx/sites-enabled/nc1 and modify client_max_body_size:

    client_max_body_size 1024M;

    Then reload nginx:

    systemctl reload nginx
  2. Edit /etc/php/8.2/fpm/php.ini like this:

    ; Maximum allowed size for uploaded files.
    ; https://php.net/upload-max-filesize
    upload_max_filesize = 1024M

    ; Maximum size of POST data that PHP will accept.
    ; Its value may be 0 to disable the limit. It is ignored if POST data reading
    ; is disabled through enable_post_data_reading.
    ; https://php.net/post-max-size
    post_max_size = 1088M

    ; Maximum amount of memory a script may consume
    ; https://php.net/memory-limit
    memory_limit = 1600M

    Then reload php8.2-fpm:

    systemctl reload php8.2-fpm

3.8 Check the security

Check the security of your NC at: https://scan.nextcloud.com/

4. More improvements

The following modifications are not strictly required.

4.1 Setup email notifications

Go to "Basic settings": https://nc1.user1.fs.al/settings/admin

On the section "Mail server" set these values

  • Send mode: SMTP
  • Enryption: None/STARTTLS
  • From address: nc1@fs.al
  • Server address: smtp.fs.al:25

Then click "Send email" to test and verify the settings.

4.2 Improve memcache

  1. Make sure that the needed packages are installed:

    apt install php-apcu php-redis
    apt install redis-server
  2. Edit (or uncomment) these lines at /etc/redis/redis.conf:

    port 0

    unixsocket /run/redis/redis-server.sock
    unixsocketperm 770

    Note: Make sure that the permissions are 770, not 700.

    systemctl restart redis
    systemctl status redis
  3. Add the user www-data to the group redis:

    usermod -aG redis www-data
  4. Append apc.enable_cli=1 to /etc/php/8.2/mods-available/apcu.ini

  5. Add these lines at /var/www/nc1/config/config.php:

    'memcache.local' => '\OC\Memcache\APCu',
    'memcache.locking' => '\OC\Memcache\Redis',
    'redis' => array(
    'host' => '/var/run/redis/redis-server.sock',
    'port' => 0,
    'timeout' => 0.0,
    ),

4.3 How ro reset a password

occ user --help
occ user:resetpassword --help
occ user:resetpassword admin

4.4 Enable HSTS

If "HTTP Strict Transport Security" is enabled, browsers will always try to use an HTTPS connection for accessing our website, and will refuse to open an HTTP (without S) page. It will also prevent site visitors from bypassing invalid certificate warnings.

This is recommended for enhanced security, but only after you are sure that you have set up everything else correctly.

It can be enabled by uncommenting this line at /etc/nginx/sites-available/nc1:

add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always;

Then reload the configuration of nginx:

nginx -t
systemctl reload nginx

4.5 Move the Data Directory

The data directory is at /var/www/nc1/data/. We can move it to /var/www/nc1-data/ like this:

occ maintenance:mode --help
occ maintenance:mode --on

mkdir -p /var/www/nc1-data/
chown www-data: /var/www/nc1-data/

cp -a /var/www/nc1/data/* /var/www/nc1-data/
cp -a /var/www/nc1/data/.ocdata /var/www/nc1-data/

nano /var/www/nc1/config/config.php # change 'datadirectory'

occ maintenance:mode --off
# rm -rf /var/www/nc1/data/