My server config ( cookbook like ) as a "pense-bete" or showcase in order to help

Hello, this is my personal pense-bete for my personal nextcloud server…
If you landed here, i hope you may find some help looking to my actual configuration.
This server is in production, up and running on a 24/7 base.
It may not being built like yours, but you may find clues…

Apache2 and nextcloud are cached directly to redis.

NEXTCLOUD HUB II - 23.0.4
based on:

  • DEBIAN Bulleyes 11.3
  • Apache 2.4.53
  • Php8.0.18
  • MariaDB 10.5.15
  • Python 3
  • Redis 6.xx
  • Brotli
    … and i may add stuff here later…

Server configuration detail UPDATED 21/04/2022

Operating system: Linux 5.10.0-13-amd64 #1 SMP Debian 5.10.106-1 (2022-03-17) x86_64 GNU/Linux
x

DATA FILESYSTEM 10TB Raid6 Array based on LVM2+MDADM, 6 physicals devices.

Webserver: Apache/2.4.53 (fpm-fcgi)

Database: mysql MariaDB 10.5.16 with Barracuda layout

PHP version:

php -v
PHP 8.0.18 (cli) (built: Apr 21 2022 10:49:51) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.18, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.18, Copyright (c), by Zend Technologies
php -m
[PHP Modules]
apcu
bcmath
bz2
calendar
Core
ctype
curl
date
dom
exif
FFI
fileinfo
filter
ftp
gd
gettext
gmp
hash
iconv
igbinary
imagick
intl
json
ldap
libxml
mbstring
mysqli
mysqlnd
openssl
pcntl
pcre
PDO
pdo_mysql
Phar
posix
readline
redis
Reflection
session
shmop
SimpleXML
soap
sockets
sodium
SPL
standard
sysvmsg
sysvsem
sysvshm
tokenizer
xml
xmlreader
xmlwriter
xsl
Zend OPcache
zip
zlib

[Zend Modules]
Zend OPcache

Nextcloud version: 23.0.4

Updated from an older Nextcloud/ownCloud or fresh install: Updated from Fresh 23.0.3 install on new server march 2022.

Where did you install Nextcloud from: Web-installer on Debian 11.3 fresh instll, manual conf for apache2 and dependencies.

List of activated apps
app:list
Enabled:
  - accessibility: 1.9.0
  - activity: 2.15.0 
 - announcementcenter: 6.1.1 
 - apporder: 0.15.0 
 - breezedark: 23.2.1 
 - bruteforcesettings: 2.4.0 
 - camerarawpreviews: 0.7.15 
 - cloud_federation_api: 1.6.0 
 - comments: 1.13.0 
 - contactsinteraction: 1.4.0  
- dav: 1.21.0  
- external: 3.10.2  
- extract: 1.3.3 
 - federatedfilesharing:1.13.0  
- federation: 1.13.0 
 - files: 1.18.0 
 - files_pdfviewer: 2.4.0 
 - files_rightclick: 1.2.0 
 - files_sharing: 1.15.0 
 - files_trashbin: 1.13.0 
 - files_versions: 1.16.0 
 - files_videoplayer: 1.12.0  
- firstrunwizard: 2.12.0 
 - flowupload: 1.1.3 
 - impersonate: 1.10.0 
 - logreader: 2.8.0 
 - lookup_server_connector: 1.11.0 
 - nextcloud_announcements: 1.12.0 
 - notifications: 2.11.1  - oauth2: 1.11.0 
 - occweb: 0.1.0  
- password_policy: 1.13.0  
- photos: 1.5.0  
- previewgenerator: 4.0.0 
 - privacy: 1.7.0  
- provisioning_api: 1.13.0  
- recommendations: 1.2.0
  - registration: 1.4.0 
 - serverinfo: 1.13.0  
- settings: 1.5.0  
- sharebymail: 1.13.0
  - sharerenamer: 3.0.0 
 - support: 1.6.0  
- survey_client: 1.11.0  
- systemtags: 1.13.0 
 - text: 3.4.1  
- theming: 1.14.0
  - twofactor_admin: 3.2.0 
 - twofactor_backupcodes: 1.12.0 
 - twofactor_email: 2.3.0 
 - twofactor_nextcloud_notification: 3.3.1
  - twofactor_totp: 6.2.0  
- twofactor_webauthn: 0.3.1  
- unsplash: 1.2.4 
 - updatenotification: 1.13.0  
- user_status: 1.3.1  
- video_converter: 1.0.4 
 - viewer: 1.7.0 
 - workflow_media_converter: 1.3.6
  - workflowengine: 2.5.0

Disabled:  
- admin_audit 
 - circles: 23.1.0  
- dashboard: 7.3.0 
 - encryption 
 - files_external 
 - user_ldap 
 - weather_status: 1.3.0


Configuration (config/config.php)
{
    "instanceid": "***REMOVED SENSITIVE VALUE***",
    "passwordsalt": "***REMOVED SENSITIVE VALUE***",
    "secret": "***REMOVED SENSITIVE VALUE***",
    "trusted_domains": [
        "n2.rkn.ovh"
    ],
    "datadirectory": "***REMOVED SENSITIVE VALUE***",
    "dbtype": "mysql",
    "version": "23.0.3.2",
    "overwrite.cli.url": "https:\/\/n2.rkn.ovh",
    "dbname": "***REMOVED SENSITIVE VALUE***",
    "dbhost": "***REMOVED SENSITIVE VALUE***",
    "dbport": "",
    "dbtableprefix": "oc_",
    "mysql.utf8mb4": true,
    "dbuser": "***REMOVED SENSITIVE VALUE***",
    "dbpassword": "***REMOVED SENSITIVE VALUE***",
    "installed": true,
    "default_language": "fr",
    "default_phone_region": "FR",
    "knowledgebaseenabled": true,
    "enable_previews": true,
    "enabledPreviewProviders": [
        "OC\\Preview\\Movie",
        "OC\\Preview\\PNG",
        "OC\\Preview\\JPEG",
        "OC\\Preview\\GIF",
        "OC\\Preview\\BMP",
        "OC\\Preview\\XBitmap",
        "OC\\Preview\\MP3",
        "OC\\Preview\\MP4",
        "OC\\Preview\\TXT",
        "OC\\Preview\\MarkDown",
        "OC\\Preview\\PDF"
    ],
    "mail_smtpmode": "smtp",
    "mail_smtpauthtype": "LOGIN",
    "mail_smtpsecure": "ssl",
    "mail_from_address": "***REMOVED SENSITIVE VALUE***",
    "mail_domain": "***REMOVED SENSITIVE VALUE***",
    "mail_smtpauth": 1,
    "mail_smtphost": "***REMOVED SENSITIVE VALUE***",
    "mail_smtpport": "465",
    "mail_smtpname": "***REMOVED SENSITIVE VALUE***",
    "mail_smtppassword": "***REMOVED SENSITIVE VALUE***",
    "cache_chunk_gc_ttl": 86400,
    "memcache.local": "\\OC\\Memcache\\Redis",
    "redis": {
        "host": "***REMOVED SENSITIVE VALUE***",
        "port": 6379,
        "password": "***REMOVED SENSITIVE VALUE***",
        "timeout": 1.5
    },
    "memcache.locking": "\\OC\\Memcache\\Redis",
    "filelocking.enabled": true,
    "filelocking.ttl": 3600,
    "check_data_directory_permissions": true,
    "twofactor_enforced": "true",
    "twofactor_enforced_groups": [
        "admin",
        "Users"
    ],
    "twofactor_enforced_excluded_groups": [],
    "maintenance": false
}

Are you using external storage, if yes which one: none, but a raid6 mdadm/lvm2 mounted as /mnt/raid6/nextcloud

Are you using encryption: no, but HTTPS and UF2 Auth for clients.

Are you using an external user-backend, if yes which one: no


**Others configuration

No alp1/Alp2, i use openssl 1.1.1.c with Letsencrypt for SSL certs.

Sorry, no caddyfile. I manually install all. This is a dedicated homemade server…

Redis configuration:


bind 127.0.0.1 ::1
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
supervised no
pidfile /var/run/redis/redis-server.pid
loglevel verbose
logfile /var/log/redis/redis-server.log
databases 16
always-show-logo yes
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir /var/lib/redis
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
replica-priority 100
 requirepass Er@x140169!
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
appendonly no
appendfilename "appendonly.aof"
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
lua-time-limit 5000
slowlog-log-slower-than 10000
latency-monitor-threshold 0
hash-max-ziplist-entries 512
hash-max-ziplist-value 6
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes



Redis log:

 2560980:C 21 Apr 2022 15:52:52.385 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
2560980:C 21 Apr 2022 15:52:52.385 # Redis version=6.0.16, bits=64, commit=00000000, modified=0, pid=2560980, just started
2560980:C 21 Apr 2022 15:52:52.385 # Configuration loaded
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 6.0.16 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 2560980
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

2560980:M 21 Apr 2022 15:52:52.389 # Server initialized
2560980:M 21 Apr 2022 15:52:52.389 * Loading RDB produced by version 6.0.16
2560980:M 21 Apr 2022 15:52:52.389 * RDB age 5 seconds
2560980:M 21 Apr 2022 15:52:52.389 * RDB memory usage when created 6.25 Mb
2560980:M 21 Apr 2022 15:52:52.404 * DB loaded from disk: 0.015 seconds
2560980:M 21 Apr 2022 15:52:52.404 * Ready to accept connections
2560980:M 21 Apr 2022 15:52:52.405 - DB 0: 6683 keys (282 volatile) in 8192 slots HT.

Apache2 configuration (obviously redacted)

/etc/apache2# nano apache2.conf

 # Global configuration
    
ServerName **redacted**
    Protocols h2c http/1.1
    Protocols h2 http/1.1
    ServerTokens Prod
    ServerSignature Off
    DefaultRuntimeDir ${APACHE_RUN_DIR}
    PidFile ${APACHE_PID_FILE}
    Timeout 800
    KeepAlive On
    MaxKeepAliveRequests 100
    KeepAliveTimeout 20
    User ${APACHE_RUN_USER}
    Group ${APACHE_RUN_GROUP}
    # logging ip needed for fail2ban parsing (deprecated)
    HostnameLookups Off
    ErrorLog ${APACHE_LOG_DIR}/error.log
    LogLevel warn
    IncludeOptional mods-enabled/*.load
    IncludeOptional mods-enabled/*.conf
    Include ports.conf

    # better security enable in vhost files
    <Directory />
        Options FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    <Directory /usr/share>
        AllowOverride All
        Require all granted
    </Directory>

    <Directory /var/www/>
        Options Indexes FollowSymLinks
 #        Options FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    AccessFileName .htaccess

    <FilesMatch "^\.ht">
        Require all denied
    </FilesMatch>

    LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
    LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %O" common
    LogFormat "%{Referer}i -> %U" referer
    LogFormat "%{User-agent}i" agent

    IncludeOptional conf-enabled/*.conf
    IncludeOptional sites-enabled/*.conf
    #EOF




/etc/apache2/sites-enabled# nano 000-default.conf

<VirtualHost *:80>
       
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html
        Protocols h2 http/1.1
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
        RewriteEngine on
        RewriteCond %{SERVER_NAME} =*redacted*
        RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
#EOF

/etc/apache2/sites-enabled# nano 000-default-le-ssl.conf

<IfModule mod_ssl.c>

<VirtualHost *:443>
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html
        Protocols h2 h2c http/1.1
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
        Include /etc/letsencrypt/options-ssl-apache.conf
        ServerName *redacted*
        SetEnv proxy-sendcl 1
        Header always set Strict-Transport-Security "max-age=15768000; includeSubDomains"
        SSLCertificateFile /etc/letsencrypt/live/*redacted*-0001/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/*redacted*-0001/privkey.pem
</VirtualHost>

SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite       EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
SSLHonorCipherOrder     on
SSLSessionTickets       off
SSLOptions +StrictRequire
SSLUseStapling          on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLStaplingCache        shmcb:/var/run/ocsp(128000)

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


</IfModule mod_ssl.c>
#EOF

mdadm

# mdadm.conf

HOMEHOST <system>
MAILADDR root
ARRAY /dev/md0 metadata=1.2 name=n2:0 UUID=0f193445:5c2d5a41:ddbafec2:71fe9019


# This configuration 07 May 2021 mdadm –detail –scan >> /etc/mdadm/mdadm.con
#    mdadm -–detail -–scan /dev/md0 >> /etc/mdadm/mdadm.con

LVM

/etc/lvm/backup# nano VG_raid6

contents = "Text Format Volume Group"
version = 1

description = "Created *after* executing 'lvcreate -nLV_nextdata -L10737418240k -p rw -C n VG_raid6'"

creation_host = "n2"    # Linux n2 5.10.0-6-amd64 #1 SMP Debian 5.10.28-1 (2021-04-09) x86_64
creation_time = 1620421024      # Fri May  7 22:57:04 2021

VG_raid6 {
        id = "tokSmy-W4U7-Uely-FimY-5ERy-Xw12-slVyDn"
        seqno = 2
        format = "lvm2"                 # informational
        status = ["RESIZEABLE", "READ", "WRITE"]
        flags = []
        extent_size = 8192              # 4 Megabytes
        max_lv = 0
        max_pv = 0
        metadata_copies = 0

        physical_volumes {

                pv0 {
                        id = "5A30CH-FaeE-izpV-Tlsc-TMAN-u7cY-TEtJ1A"
                        device = "/dev/md0"     # Hint only

                        status = ["ALLOCATABLE"]
                        flags = []
                        dev_size = 23441310720  # 10.9157 Terabytes
                        pe_start = 3072
                        pe_count = 2861487      # 10.9157 Terabytes
                }
        }

        logical_volumes {

                LV_nextdata {
                        id = "0HVGBm-LMM6-dYYQ-y5me-zMPm-1Qlg-8weqYb"
                        status = ["READ", "WRITE", "VISIBLE"]
                        flags = []
                        creation_time = 1620421024      # 2021-05-07 22:57:04 +0200
                        creation_host = "n2"
                        segment_count = 1

                        segment1 {
                                start_extent = 0
                                extent_count = 2621440  # 10 Terabytes

                                type = "striped"
                                stripe_count = 1        # linear

                                stripes = [
                                        "pv0", 0
                                ]
                        }
                }
        }

}


contents = "Text Format Volume Group"
version = 1

description = "Created *after* executing 'vgcfgbackup'"

creation_host = "n2"    # Linux n2 4.19.0-16-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64
creation_time = 1620321828      # Thu May  6 19:23:48 2021

n2-vg {
        id = "LNrIvZ-atn0-Bw2n-oL5O-YewP-1zm8-ZiT2Sg"
        seqno = 3
        format = "lvm2"                 # informational
        status = ["RESIZEABLE", "READ", "WRITE"]
        flags = []
        extent_size = 8192              # 4 Megabytes
        max_lv = 0
        max_pv = 0
        metadata_copies = 0

        physical_volumes {

                pv0 {
                        id = "xjDUeE-E5EK-Ylia-AcSw-Ht7I-DQLh-tW6PN7"
                        device = "/dev/sdg3"    # Hint only

                        status = ["ALLOCATABLE"]
                        flags = []
                        dev_size = 935651328    # 446.153 Gigabytes
                        pe_start = 2048
                        pe_count = 114215       # 446.152 Gigabytes
                }
        }

        logical_volumes {

                root {
                        id = "xuoBH5-lyu2-2Ny3-C5n1-73ZJ-X5vz-noeFiJ"
                        status = ["READ", "WRITE", "VISIBLE"]
                        flags = []
                        creation_time = 1620320455      # 2021-05-06 19:00:55 +0200
                        creation_host = "n2"
                        segment_count = 1

                        segment1 {
                                start_extent = 0
                                extent_count = 113970   # 445.195 Gigabytes

                                type = "striped"
                                stripe_count = 1        # linear

                                stripes = [
                                        "pv0", 0
                                ]
                        }
                }

                swap_1 {
                        id = "RnlEyd-qsiP-GCCt-CVBZ-Iuhe-kTmC-jtJdQ3"
                        status = ["READ", "WRITE", "VISIBLE"]
                        flags = []
                        creation_time = 1620320455      # 2021-05-06 19:00:55 +0200
                        creation_host = "n2"
                        segment_count = 1

                        segment1 {
                                start_extent = 0
                                extent_count = 245      # 980 Megabytes

                                type = "striped"
                                stripe_count = 1        # linear

                                stripes = [
                                        "pv0", 113970
                                ]
                        }
                }
        }

}

PHP

As php 7 to 8 are almost the same, here the conf files ( redacted ) for help…
Remember, some things are server relative, so fine tuning will be needed…

  1. PHP8.0 apache2 conf files

Short trick, the apache/cli/ are the same…

located /etc/php/8.0/apache2

[PHP]
; minimum conf file for my nextcloud test plateform, redacted.

engine = On
short_open_tag = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func =
serialize_precision = -1
disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
disable_classes =
zend.enable_gc = On
zend.exception_ignore_args = On
zend.exception_string_param_max_len = 0
expose_php = Off
max_execution_time = 900
max_input_time = 300
memory_limit = 1024M
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = Off
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
variables_order = "GPCS"
request_order = "GP"
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 999GB
auto_append_file =
default_mimetype = "text/html"
default_charset = "UTF-8"
doc_root =
user_dir =
enable_dl = Off
file_uploads = On
upload_max_filesize = 999GB

max_file_uploads = 20
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 60
zend_extension=opcache
cli_server.color = On
date.timezone = Europe/Paris
[Pdo_mysql]
pdo_mysql.default_socket=

[mail function]
SMTP = localhost
smtp_port = 25
mail.add_x_header = Off

[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode = 1

[Session]
session.save_handler = redis
session.save_path = "tcp://localhost:6379?auth=redacted"
session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.cookie_samesite =
session.serialize_handler = php
session.gc_probability = 0
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.sid_length = 26
session.trans_sid_tags = "a=href,area=href,frame=src,form="
session.sid_bits_per_character = 5

[Assertion]
zend.assertions = -1



[Tidy]
tidy.clean_output = Off

[soap]
soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400
soap.wsdl_cache_limit = 5


[opcache]
opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=1
opcache.save_comments=1
  1. php-fpm

located /etc/php/8.0/fpm

[global]
pid = /run/php/php8.0-fpm.pid
error_log = /var/log/php8.0-fpm.log

include=/etc/php/8.0/fpm/pool.d/*.conf

pool.d www.conf

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.process_idle_timeout = 99s;
;pm.max_requests = 500
;pm.status_listen = 127.0.0.1:9001

EOF

Here is also a list of the package installed on my Debian bulleyes:

updated 04/21/2022
added php conf 04/28/2022