From a50255f4e54fab1faf11554e5de4c493b369b03c Mon Sep 17 00:00:00 2001 From: Nicolas Gelot Date: Mon, 31 Mar 2025 17:59:21 +0200 Subject: [PATCH 1/3] Rework docker compose --- .env.example | 47 ++++++ README.md | 6 +- config/nginx/sites-enabled/.keep | 0 config/nginx/sites-enabled/resolver.conf | 1 - .../nginx/templates/autoconfig.conf.template | 13 ++ .../nginx/templates/default.conf.template | 18 +-- config/nginx/templates/mta-sts.conf.template | 10 ++ .../templates/postfixadmin.conf.template | 10 ++ config/nginx/templates/rspamd.conf.template | 13 ++ config/nginx/templates/welcome.conf.template | 13 ++ .../docker-compose.yml => docker-compose.yml | 145 ++++++++---------- templates/nginx/sites-enabled/autoconfig.conf | 32 ---- templates/nginx/sites-enabled/mta-sts.conf | 12 -- .../nginx/sites-enabled/postfixadmin.conf | 32 ---- templates/nginx/sites-enabled/rspamd.conf | 32 ---- templates/nginx/sites-enabled/welcome.conf | 32 ---- 16 files changed, 176 insertions(+), 240 deletions(-) create mode 100644 .env.example delete mode 100644 config/nginx/sites-enabled/.keep delete mode 100644 config/nginx/sites-enabled/resolver.conf create mode 100644 config/nginx/templates/autoconfig.conf.template rename templates/nginx/sites-enabled/nextcloud.conf => config/nginx/templates/default.conf.template (92%) create mode 100644 config/nginx/templates/mta-sts.conf.template create mode 100644 config/nginx/templates/postfixadmin.conf.template create mode 100644 config/nginx/templates/rspamd.conf.template create mode 100644 config/nginx/templates/welcome.conf.template rename templates/docker-compose/docker-compose.yml => docker-compose.yml (53%) delete mode 100644 templates/nginx/sites-enabled/autoconfig.conf delete mode 100644 templates/nginx/sites-enabled/mta-sts.conf delete mode 100644 templates/nginx/sites-enabled/postfixadmin.conf delete mode 100644 templates/nginx/sites-enabled/rspamd.conf delete mode 100644 templates/nginx/sites-enabled/welcome.conf diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..d09ebe9 --- /dev/null +++ b/.env.example @@ -0,0 +1,47 @@ +# server +DOMAIN=localhost +ADD_DOMAINS= +VHOSTS_ACCOUNTS=welcome.localhost +VIRTUAL_HOST=autoconfig.localhost,autodiscover.localhost +NC_HOST_IP= + +# mail +DRIVE_SMTP_PASSWORD=123456 +RSPAMD_PASSWORD=123456 +ENABLE_POP3=1 +DISABLE_RATELIMITING=true +RELAY_NETWORKS=172.16.0.0/12 +POSTFIXADMIN_SSH_PASSWORD=123456 +SMTP_HOST=mail.localhost +SMTP_FROM=welcome@localhost +SMTP_PW=123456 + +# mail autodiscover +AUTODISCOVER_AM_UUID=abcd +AUTODISCOVER_AP_UUID=abcd + +# database +MYSQL_ROOT_PASSWORD=123456 +DBPASS=123456 +DBHOST=mariadb +PFDB_DB=postfix +PFDB_USR=postfix +MYSQL_DATABASE_NC=nextcloud +MYSQL_USER_NC=nextcloud +MYSQL_DATABASE_NC=nextcloud +MYSQL_PASSWORD_NC=123456 + +# welcome +WELCOME_SECRET_SHA=abcdefgh +WEBSITE_SECRET=789456123 +ECLOUD_ACCOUNTS_SECRET=123456 + +# nextcloud +NEXTCLOUD_ADMIN_USER=admin +NEXTCLOUD_ADMIN_PASSWORD=@adm1n +NEXTCLOUD_EMAIL_RECOVERY_APP_SECRET=123456 +CREATE_ACCOUNT_PASSWORD=123456 + + + + diff --git a/README.md b/README.md index 7f566ab..c6981cf 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# Ecloud Selfhosting (Beta) +# Ecloud Selfhosting This project allows users to install ecloud services on their own server, using a single identity. -This way, a user can use [/e/OS](https://e.foundation/products/) on a smartphone while self-hosting and syncing data: +This way, a user can use [/e/OS](https://e.foundation/e-os/) on a smartphone while self-hosting and syncing data: 1. pictures, videos, files... 2. calendar 3. contacts @@ -10,7 +10,7 @@ This way, a user can use [/e/OS](https://e.foundation/products/) on a smartphone 5. tasks 6. device configuration... -The setup, which is relying on NextCloud, Postfix, and other open source components, is very close to the one used on [ecloud.global](https://ecloud.global). +The setup, which is relying on NextCloud, Postfix, and other open source components, is very close to the one used on [murena.io](https://murena.io). Important note: this project is currently in beta. You should have some experience with Linux server administration if you want to use it. The current setup makes updates difficult, diff --git a/config/nginx/sites-enabled/.keep b/config/nginx/sites-enabled/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/config/nginx/sites-enabled/resolver.conf b/config/nginx/sites-enabled/resolver.conf deleted file mode 100644 index f736959..0000000 --- a/config/nginx/sites-enabled/resolver.conf +++ /dev/null @@ -1 +0,0 @@ -resolver 127.0.0.11 ; diff --git a/config/nginx/templates/autoconfig.conf.template b/config/nginx/templates/autoconfig.conf.template new file mode 100644 index 0000000..0c657c6 --- /dev/null +++ b/config/nginx/templates/autoconfig.conf.template @@ -0,0 +1,13 @@ +server { + listen 80; + listen [::]:80; + server_name autoconfig.${DOMAIN}; + + include /etc/nginx/params/ssl_params; + include /etc/nginx/params/headers_params; + + location / { + proxy_pass http://mail-autodiscover-autoconfig:80; + include /etc/nginx/params/proxy_params; + } +} diff --git a/templates/nginx/sites-enabled/nextcloud.conf b/config/nginx/templates/default.conf.template similarity index 92% rename from templates/nginx/sites-enabled/nextcloud.conf rename to config/nginx/templates/default.conf.template index 2252509..94202c7 100644 --- a/templates/nginx/sites-enabled/nextcloud.conf +++ b/config/nginx/templates/default.conf.template @@ -3,24 +3,12 @@ upstream php-handler { } server { - listen 8000; - server_name @@@DOMAIN@@@; - location /.well-known/acme-challenge/ { - alias /etc/letsencrypt/acme-challenge/.well-known/acme-challenge/; - } - location / { - return 301 https://$host$request_uri; - } -} - -server { - listen 4430 ssl; - server_name @@@DOMAIN@@@; + listen 80; + listen [::]:80; + server_name ${DOMAIN}; root /var/www/html; - ssl_certificate /certs/live/@@@DOMAIN@@@/fullchain.pem; - ssl_certificate_key /certs/live/@@@DOMAIN@@@/privkey.pem; include /etc/nginx/params/ssl_params; # We include these headers directly because some are already set by Nextcloud. diff --git a/config/nginx/templates/mta-sts.conf.template b/config/nginx/templates/mta-sts.conf.template new file mode 100644 index 0000000..619b919 --- /dev/null +++ b/config/nginx/templates/mta-sts.conf.template @@ -0,0 +1,10 @@ +server { + listen 80; + listen [::]:80; + server_name mta-sts.${DOMAIN}; + + include /etc/nginx/params/ssl_params; + include /etc/nginx/params/headers_params; + + root /var/www/mta-sts; +} diff --git a/config/nginx/templates/postfixadmin.conf.template b/config/nginx/templates/postfixadmin.conf.template new file mode 100644 index 0000000..56ab816 --- /dev/null +++ b/config/nginx/templates/postfixadmin.conf.template @@ -0,0 +1,10 @@ +server { + listen 80; + listen [::]:80; + server_name mail.${DOMAIN}; + + location / { + proxy_pass http://postfixadmin:80; + include /etc/nginx/params/proxy_params; + } +} diff --git a/config/nginx/templates/rspamd.conf.template b/config/nginx/templates/rspamd.conf.template new file mode 100644 index 0000000..ce7aa01 --- /dev/null +++ b/config/nginx/templates/rspamd.conf.template @@ -0,0 +1,13 @@ +server { + listen 80; + listen [::]:80; + server_name spam.${DOMAIN}; + + include /etc/nginx/params/ssl_params; + include /etc/nginx/params/headers_params; + + location / { + proxy_pass http://mailserver:11334; + include /etc/nginx/params/proxy_params; + } +} diff --git a/config/nginx/templates/welcome.conf.template b/config/nginx/templates/welcome.conf.template new file mode 100644 index 0000000..4e86c3f --- /dev/null +++ b/config/nginx/templates/welcome.conf.template @@ -0,0 +1,13 @@ +server { + listen 80; + listen [::]:80; + server_name welcome.${DOMAIN}; + + include /etc/nginx/params/ssl_params; + include /etc/nginx/params/headers_params; + + location / { + proxy_pass http://welcome:80; + include /etc/nginx/params/proxy_params; + } +} diff --git a/templates/docker-compose/docker-compose.yml b/docker-compose.yml similarity index 53% rename from templates/docker-compose/docker-compose.yml rename to docker-compose.yml index c951ea3..55d2c45 100644 --- a/templates/docker-compose/docker-compose.yml +++ b/docker-compose.yml @@ -1,17 +1,12 @@ -version: '3' - services: mailserver: - image: mailserver2/mailserver:1.1.16 - container_name: mailserver + image: mailserver2/mailserver:1.1.22 domainname: ${DOMAIN} # Mail server A/MX/FQDN & reverse PTR = mail.${DOMAIN}. hostname: mail - restart: always - networks: - - default + restart: unless-stopped ports: - "25:25" # SMTP - Required - - "110:110" # POP3 STARTTLS - Optional - For webmails/desktop clients + - "110:110" # POP3 STARTTLS - Optional - For webmail:s/desktop clients - "143:143" # IMAP STARTTLS - Optional - For webmails/desktop clients # - "465:465" # SMTPS SSL/TLS - Optional - Enabled for compatibility reason, otherwise disabled - "587:587" # Submission STARTTLS - Optional - For webmails/desktop clients @@ -24,53 +19,59 @@ services: - ADD_DOMAINS=${ADD_DOMAINS} - ENABLE_POP3=${ENABLE_POP3} - DISABLE_RATELIMITING=${DISABLE_RATELIMITING} - - RELAY_NETWORKS=172.16.0.0/12 + - RELAY_NETWORKS=${RELAY_NETWORKS} # Full list of options: https://github.com/hardware/mailserver#environment-variables + labels: + - "traefik.enable=true" + - "traefik.docker.network=proxy" + - "traefik.http.routers.spam.entrypoints=websecure" + - "traefik.http.routers.spam.rule=Host(`spam.${DOMAIN}`)" + - "traefik.http.routers.spam.service=spam" + - "traefik.http.routers.spam.tls=true" + - "traefik.http.routers.spam.tls.certresolver=letsencrypt" + - "traefik.http.routers.spam.tls.domains[0].main=mail.${DOMAIN}" + - "traefik.http.routers.spam.tls.domains[0].sans=spam.${DOMAIN}" + - "traefik.http.routers.spam.tls.options=default" + - "traefik.http.services.spam.loadbalancer.server.port=11334" + - "traefik.http.services.spam.loadbalancer.server.scheme=http" volumes: - - /mnt/repo-base/volumes/mail:/var/mail - - /mnt/repo-base/config/letsencrypt/certstore:/etc/letsencrypt - - /mnt/repo-base/config/mail/dovecot/10-mail.conf:/etc/dovecot/conf.d/10-mail.conf - - /mnt/repo-base/config/mail/dovecot/90-quota.conf:/etc/dovecot/conf.d/90-quota.conf - - /mnt/repo-base/config/mail/dovecot/90-sieve.conf:/etc/dovecot/conf.d/90-sieve.conf - - /mnt/repo-base/config/mail/rspamd/multimap.conf:/etc/rspamd/local.d/multimap.conf - - /mnt/repo-base/config/mail/rspamd/ecloud:/etc/rspamd/local.d/ecloud - - /mnt/repo-base/config/mail/rspamd/ratelimit.conf:/etc/rspamd/local.d/ratelimit.conf - - /mnt/repo-base/config/mail/clamav/freshclam.conf:/etc/clamav/freshclam.conf + - ${DEPLOYMENT_PATH:-.}/volumes/mail:/var/mail + - ${DEPLOYMENT_PATH:-.}/volumes/traefik/acme:/etc/letsencrypt/acme + - ${DEPLOYMENT_PATH:-.}/config/mail/dovecot/10-mail.conf:/etc/dovecot/conf.d/10-mail.conf + - ${DEPLOYMENT_PATH:-.}/config/mail/dovecot/90-quota.conf:/etc/dovecot/conf.d/90-quota.conf + - ${DEPLOYMENT_PATH:-.}/config/mail/dovecot/90-sieve.conf:/etc/dovecot/conf.d/90-sieve.conf + - ${DEPLOYMENT_PATH:-.}/config/mail/rspamd/multimap.conf:/etc/rspamd/local.d/multimap.conf + - ${DEPLOYMENT_PATH:-.}/config/mail/rspamd/ratelimit.conf:/etc/rspamd/local.d/ratelimit.conf + - ${DEPLOYMENT_PATH:-.}/config/mail/clamav/freshclam.conf:/etc/clamav/freshclam.conf depends_on: - mariadb - redis postfixadmin: image: registry.gitlab.e.foundation/e/infra/docker-postfixadmin:2.0.1 - container_name: postfixadmin - restart: always - networks: - - default + restart: unless-stopped environment: - DBPASS=${DBPASS} - - DBHOST=mariadb + - DBHOST=${DBHOST} - DOMAIN=${DOMAIN} - DRIVE_SMTP_PASSWORD=${DRIVE_SMTP_PASSWORD} - POSTFIXADMIN_SSH_PASSWORD=${POSTFIXADMIN_SSH_PASSWORD} - POSTFIXADMIN_DB_TYPE=mysqli - - POSTFIXADMIN_DB_HOST=mariadb - - POSTFIXADMIN_DB_USER=postfix - - POSTFIXADMIN_DB_NAME=postfix + - POSTFIXADMIN_DB_HOST=${DBHOST} + - POSTFIXADMIN_DB_USER=${PFDB_DB} + - POSTFIXADMIN_DB_NAME=${PFDB_USR} - POSTFIXADMIN_DB_PASSWORD=${DBPASS} - POSTFIXADMIN_SMTP_SERVER=mail.${DOMAIN} - POSTFIXADMIN_SMTP_PORT=587 volumes: - - /mnt/repo-base/volumes/mail:/var/mail + - ${DEPLOYMENT_PATH:-.}/volumes/mail:/var/mail depends_on: - mailserver - mariadb mariadb: - image: mariadb:10.3 - container_name: mariadb - restart: always - networks: - - default + image: mariadb:11.7 + restart: unless-stopped environment: # Note: These variables are only used for the first start. Later changes are ignored. - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} @@ -78,28 +79,24 @@ services: - MYSQL_USER=${PFDB_USR} - MYSQL_PASSWORD=${DBPASS} volumes: - - /mnt/repo-base/volumes/mysql/db/data:/var/lib/mysql - - /mnt/repo-base/config/mariadb/:/etc/mysql/conf.d/:ro + - ${DEPLOYMENT_PATH:-.}/volumes/mysql/db/data:/var/lib/mysql + - ${DEPLOYMENT_PATH:-.}/config/mariadb/:/etc/mysql/conf.d/:ro redis: - image: redis:6.2-alpine - container_name: redis - restart: always - networks: - - default - command: redis-server --appendonly yes + image: redis:7.4-alpine + restart: unless-stopped + command: redis-server --maxmemory 8G --maxmemory-policy allkeys-lru volumes: - - /mnt/repo-base/volumes/redis/db:/data - - /mnt/repo-base/volumes/redis/tmp:/tmp/redis + - ${DEPLOYMENT_PATH:-.}/volumes/redis/db:/data + - ${DEPLOYMENT_PATH:-.}/volumes/redis/tmp:/tmp/redis welcome: image: registry.gitlab.e.foundation/e/infra/docker-welcome:2.5.0 - container_name: welcome environment: - DOMAINS=${VHOSTS_ACCOUNTS} - DOMAIN=${DOMAIN} - IS_WELCOME=true - - PFDB_HOST=mariadb + - PFDB_HOST=${DBHOST} - PFDB_DB=${PFDB_DB} - PFDB_USR=${PFDB_USR} - PFDB_PW=${DBPASS} @@ -117,49 +114,41 @@ services: - NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD} - NEXTCLOUD_EMAIL_RECOVERY_APP_SECRET=${NEXTCLOUD_EMAIL_RECOVERY_APP_SECRET} - CREATE_ACCOUNT_PASSWORD=${CREATE_ACCOUNT_PASSWORD} - restart: always - networks: - - default + restart: unless-stopped volumes: - - /mnt/repo-base/volumes/accounts:/var/accounts - - /mnt/repo-base/config/welcome/apache2/remoteip.conf:/etc/apache2/conf-available/remoteip.conf - extra_hosts: - - "${DOMAIN}:${NC_HOST_IP}" - - "mail.${DOMAIN}:${NC_HOST_IP}" + - ${DEPLOYMENT_PATH:-.}/volumes/accounts:/var/accounts + - ${DEPLOYMENT_PATH:-.}/config/welcome/apache2/remoteip.conf:/etc/apache2/conf-available/remoteip.conf + # extra_hosts: + # - "${DOMAIN}:${NC_HOST_IP}" + # - "mail.${DOMAIN}:${NC_HOST_IP}" nextcloud: image: registry.gitlab.e.foundation/e/infra/ecloud/nextcloud/selfhost:26-0-8-23 - container_name: nextcloud - restart: always - networks: - - default + restart: unless-stopped environment: - MYSQL_DATABASE=${MYSQL_DATABASE_NC} - MYSQL_USER=${MYSQL_USER_NC} - MYSQL_PASSWORD=${MYSQL_PASSWORD_NC} - - MYSQL_HOST=mariadb + - MYSQL_HOST={DBHOST} - NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER} # below ENV disabled so NC container do not start install # - NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD} - OVERWRITEPROTOCOL=https - NEXTCLOUD_EMAIL_RECOVERY_APP_SECRET=${NEXTCLOUD_EMAIL_RECOVERY_APP_SECRET} volumes: - - /mnt/repo-base/volumes/nextcloud/html:/var/www/html/ - - /mnt/repo-base/volumes/nextcloud/data:/var/www/data/ - - /mnt/repo-base/config/nextcloud/x-fpm-overloads.conf:/usr/local/etc/php-fpm.d/x-fpm-overloads.conf - - /mnt/repo-base/config/nextcloud/x-php-overloads.ini:/usr/local/etc/php/conf.d/x-php-overloads.ini - - /mnt/repo-base/volumes/nextcloud/log:/var/www/log/ - - /mnt/repo-base/volumes/redis/db:/tmp/redis + - ${DEPLOYMENT_PATH:-.}/volumes/nextcloud/html:/var/www/html/ + - ${DEPLOYMENT_PATH:-.}/volumes/nextcloud/data:/var/www/data/ + - ${DEPLOYMENT_PATH:-.}/config/nextcloud/x-fpm-overloads.conf:/usr/local/etc/php-fpm.d/x-fpm-overloads.conf + - ${DEPLOYMENT_PATH:-.}/config/nextcloud/x-php-overloads.ini:/usr/local/etc/php/conf.d/x-php-overloads.ini + - ${DEPLOYMENT_PATH:-.}/volumes/nextcloud/log:/var/www/log/ + - ${DEPLOYMENT_PATH:-.}/volumes/redis/db:/tmp/redis depends_on: - mariadb - redis mail-autodiscover-autoconfig: image: wdes/mail-autodiscover-autoconfig:latest - container_name: mail-autodiscover-autoconfig - restart: always - networks: - - default + restart: unless-stopped environment: ROCKET_PROFILE: production ROCKET_ADDRESS: "0.0.0.0" @@ -170,29 +159,23 @@ services: POP_HOSTNAME: ${SMTP_HOST} SMTP_HOSTNAME: ${SMTP_HOST} volumes: - - /mnt/repo-base/config/autodiscover/xml:/usr/lib/mail-autodiscover-autoconfig/templates/xml + - ${DEPLOYMENT_PATH:-.}/config/autodiscover/xml:/usr/lib/mail-autodiscover-autoconfig/templates/xml nginx: image: nginx:stable-alpine - container_name: nginx restart: unless-stopped - networks: - - default + environment: + DOMAIN: ${DOMAIN} ports: - - "80:8000" - - "443:4430" + - "8000:80" volumes: - - /mnt/repo-base/config/nginx/sites-enabled:/etc/nginx/conf.d/ - - /mnt/repo-base/config/nginx/params:/etc/nginx/params/ - - /mnt/repo-base/config/letsencrypt/certstore:/certs - - /mnt/repo-base/config/nginx/passwds:/passwds - - /mnt/repo-base/config/letsencrypt/acme-challenge:/etc/letsencrypt/acme-challenge - - /mnt/repo-base/volumes/nextcloud/html:/var/www/html - - /mnt/repo-base/config/mta-sts:/var/www/mta-sts + - ${DEPLOYMENT_PATH:-.}/config/nginx/templates:/etc/nginx/templates + - ${DEPLOYMENT_PATH:-.}/config/nginx/params:/etc/nginx/params/ + - ${DEPLOYMENT_PATH:-.}/volumes/nextcloud/html:/var/www/html + - ${DEPLOYMENT_PATH:-.}/config/mta-sts:/var/www/mta-sts depends_on: - nextcloud - mail-autodiscover-autoconfig - postfixadmin - welcome - mailserver - diff --git a/templates/nginx/sites-enabled/autoconfig.conf b/templates/nginx/sites-enabled/autoconfig.conf deleted file mode 100644 index a590f52..0000000 --- a/templates/nginx/sites-enabled/autoconfig.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 8000; - server_name @@@SERVICE@@@.@@@DOMAIN@@@; - location /.well-known/acme-challenge/ { - alias /etc/letsencrypt/acme-challenge/.well-known/acme-challenge/; - } - location / { - return 301 https://$host$request_uri; - } -} - -server { - listen 4430 ssl; - server_name @@@SERVICE@@@.@@@DOMAIN@@@; - - ssl_certificate /certs/live/@@@SERVICE@@@.@@@DOMAIN@@@/fullchain.pem; - ssl_certificate_key /certs/live/@@@SERVICE@@@.@@@DOMAIN@@@/privkey.pem; - - include /etc/nginx/params/ssl_params; - include /etc/nginx/params/headers_params; - - #add_header Strict-Transport-Security "max-age=;"; - #client_max_body_size M; - - #auth_basic "Who's this?"; - #auth_basic_user_file /passwds/.htpasswd; - - location / { - proxy_pass http://mail-autodiscover-autoconfig:80; - include /etc/nginx/params/proxy_params; - } -} diff --git a/templates/nginx/sites-enabled/mta-sts.conf b/templates/nginx/sites-enabled/mta-sts.conf deleted file mode 100644 index a3110a7..0000000 --- a/templates/nginx/sites-enabled/mta-sts.conf +++ /dev/null @@ -1,12 +0,0 @@ -server { - listen 4430 ssl http2; - server_name mta-sts.@@@DOMAIN@@@; - - ssl_certificate /certs/live/mta-sts.@@@DOMAIN@@@/fullchain.pem; - ssl_certificate_key /certs/live/mta-sts.@@@DOMAIN@@@/privkey.pem; - - include /etc/nginx/params/ssl_params; - include /etc/nginx/params/headers_params; - - root /var/www/mta-sts; -} diff --git a/templates/nginx/sites-enabled/postfixadmin.conf b/templates/nginx/sites-enabled/postfixadmin.conf deleted file mode 100644 index ae73561..0000000 --- a/templates/nginx/sites-enabled/postfixadmin.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 8000; - server_name mail.@@@DOMAIN@@@; - location /.well-known/acme-challenge/ { - alias /etc/letsencrypt/acme-challenge/.well-known/acme-challenge/; - } - location / { - return 301 https://$host$request_uri; - } -} - -server { - listen 4430 ssl; - server_name mail.@@@DOMAIN@@@; - - ssl_certificate /certs/live/mail.@@@DOMAIN@@@/fullchain.pem; - ssl_certificate_key /certs/live/mail.@@@DOMAIN@@@/privkey.pem; - - include /etc/nginx/params/ssl_params; - include /etc/nginx/params/headers_params; - - #add_header Strict-Transport-Security "max-age=;"; - #client_max_body_size M; - - #auth_basic "Who's this?"; - #auth_basic_user_file /passwds/.htpasswd; - - location / { - proxy_pass http://postfixadmin:80; - include /etc/nginx/params/proxy_params; - } -} diff --git a/templates/nginx/sites-enabled/rspamd.conf b/templates/nginx/sites-enabled/rspamd.conf deleted file mode 100644 index 69e6dd7..0000000 --- a/templates/nginx/sites-enabled/rspamd.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 8000; - server_name spam.@@@DOMAIN@@@; - location /.well-known/acme-challenge/ { - alias /etc/letsencrypt/acme-challenge/.well-known/acme-challenge/; - } - location / { - return 301 https://$host$request_uri; - } -} - -server { - listen 4430 ssl; - server_name spam.@@@DOMAIN@@@; - - ssl_certificate /certs/live/spam.@@@DOMAIN@@@/fullchain.pem; - ssl_certificate_key /certs/live/spam.@@@DOMAIN@@@/privkey.pem; - - include /etc/nginx/params/ssl_params; - include /etc/nginx/params/headers_params; - - #add_header Strict-Transport-Security "max-age=;"; - #client_max_body_size M; - - #auth_basic "Who's this?"; - #auth_basic_user_file /passwds/.htpasswd; - - location / { - proxy_pass http://mailserver:11334; - include /etc/nginx/params/proxy_params; - } -} diff --git a/templates/nginx/sites-enabled/welcome.conf b/templates/nginx/sites-enabled/welcome.conf deleted file mode 100644 index bcbd5f3..0000000 --- a/templates/nginx/sites-enabled/welcome.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 8000; - server_name welcome.@@@DOMAIN@@@; - location /.well-known/acme-challenge/ { - alias /etc/letsencrypt/acme-challenge/.well-known/acme-challenge/; - } - location / { - return 301 https://$host$request_uri; - } -} - -server { - listen 4430 ssl; - server_name welcome.@@@DOMAIN@@@; - - ssl_certificate /certs/live/welcome.@@@DOMAIN@@@/fullchain.pem; - ssl_certificate_key /certs/live/welcome.@@@DOMAIN@@@/privkey.pem; - - include /etc/nginx/params/ssl_params; - include /etc/nginx/params/headers_params; - - #add_header Strict-Transport-Security "max-age=;"; - #client_max_body_size M; - - #auth_basic "Who's this?"; - #auth_basic_user_file /passwds/.htpasswd; - - location / { - proxy_pass http://welcome:80; - include /etc/nginx/params/proxy_params; - } -} -- GitLab From 33623123a0604e163d12b33f10362c6f1a219899 Mon Sep 17 00:00:00 2001 From: Nicolas Gelot Date: Wed, 2 Apr 2025 22:16:51 +0200 Subject: [PATCH 2/3] Polish nextcloud config --- .env.example | 17 ++++---- README.md | 22 +++++----- config/mariadb/ecloud.cnf | 22 ++++++---- config/mariadb/init.sql | 10 +++++ config/nextcloud/x-fpm-overloads.conf | 7 ---- config/nextcloud/x-php-overloads.ini | 8 ---- docker-compose.yml | 59 ++++++++++++--------------- 7 files changed, 67 insertions(+), 78 deletions(-) create mode 100644 config/mariadb/init.sql delete mode 100644 config/nextcloud/x-fpm-overloads.conf delete mode 100644 config/nextcloud/x-php-overloads.ini diff --git a/.env.example b/.env.example index d09ebe9..4eb999c 100644 --- a/.env.example +++ b/.env.example @@ -21,19 +21,20 @@ AUTODISCOVER_AM_UUID=abcd AUTODISCOVER_AP_UUID=abcd # database +DBHOST=mariadb MYSQL_ROOT_PASSWORD=123456 +DBUSER=selfhost DBPASS=123456 -DBHOST=mariadb PFDB_DB=postfix -PFDB_USR=postfix MYSQL_DATABASE_NC=nextcloud -MYSQL_USER_NC=nextcloud -MYSQL_DATABASE_NC=nextcloud -MYSQL_PASSWORD_NC=123456 + +# redis +REDIS_HOST=redis # welcome +WELCOME_SECRET=123456 WELCOME_SECRET_SHA=abcdefgh -WEBSITE_SECRET=789456123 +WEBSITE_SECRET=123456 ECLOUD_ACCOUNTS_SECRET=123456 # nextcloud @@ -41,7 +42,3 @@ NEXTCLOUD_ADMIN_USER=admin NEXTCLOUD_ADMIN_PASSWORD=@adm1n NEXTCLOUD_EMAIL_RECOVERY_APP_SECRET=123456 CREATE_ACCOUNT_PASSWORD=123456 - - - - diff --git a/README.md b/README.md index c6981cf..c1d9eae 100644 --- a/README.md +++ b/README.md @@ -83,17 +83,15 @@ In the following text, `$DOMAIN` refers to the domain (`youdomain.com`) that you ### Start bootstrap process -Login to the server via ssh as root (on Linux/macOS the ssh client is available out of the box, on Windows you need to use an ssh client like [Putty](https://www.putty.org/) for example). - -Execute these commands and follow the on-screen instructions: - +Copy the environment file `.env.example` and name it `.env` in the root directory of the project, then update it accordingly. +Once done you can run the project with: ``` -$ ssh root@$DOMAIN -# git clone https://gitlab.e.foundation/e/infra/ecloud-selfhosting.git --single-branch --branch master /mnt/repo-base -# cd /mnt/repo-base -# bash scripts/bootstrap.sh +chown -R '33':'33' volumes/nextcloud/{html,data,log}` +mkdir -p ./volumes/nextcloud/{html,data,log} && sudo chown -R '33':'33' volumes/nextcloud/{html,data,log} +docker compose up -d ``` -The setup script will ask you to input some details of your setup (like your domain name) and to setup additional DNS records (the two A records plus the PTR record were set already above). + + Example session for yourdomain.com: ``` @@ -180,7 +178,7 @@ Your credentials for postfix admin (https://mail.yourdomain.com) are: user/pass ## Privacy - The default behaviour of nextcloud is that all users on a server can see and share with each other. As this may make sense on a company or family environment, we keep this behaviour in the `selfhost` image tag. -- For public instances like our [ecloud](https://ecloud.global), we provide the `selfhost-privacy` tag with the enhanced privacy approach. +- For public instances like our [murena.io](https://murena.io), we provide the `selfhost-privacy` tag with the enhanced privacy approach. - Some of the improvements are: - Users cannot find each other on search unless they use the full email address - User statuses are not available globally for other users to view @@ -193,11 +191,11 @@ Your credentials for postfix admin (https://mail.yourdomain.com) are: user/pass - "Allow users to publish their data to a global and public address book" -## Setting up /e/ OS with /e/ selfhosting +## Setting up /e/OS with /e/ selfhosting For a new installation, enter login (email address - username@yourdomain.com), password and selfhosting domain FQDN in the fist time usage wizard. -If you already have /e/ OS installed, you can add your selfhosting domain under +If you already have /e/OS installed, you can add your selfhosting domain under Settings->Users & accounts->Add account->/e/ account diff --git a/config/mariadb/ecloud.cnf b/config/mariadb/ecloud.cnf index e1b9b82..f437fa8 100644 --- a/config/mariadb/ecloud.cnf +++ b/config/mariadb/ecloud.cnf @@ -1,26 +1,32 @@ [server] -performance_schema = on skip_name_resolve = 1 - -innodb_buffer_pool_size=1G +innodb_buffer_pool_size = 128M innodb_buffer_pool_instances = 1 -innodb_buffer_pool_chunk_size = 1G innodb_flush_log_at_trx_commit = 2 -innodb_log_buffer_size = 256M +innodb_log_buffer_size = 32M innodb_max_dirty_pages_pct = 90 -innodb_io_capacity=4000 - query_cache_type = 1 query_cache_limit = 2M query_cache_min_res_unit = 2k query_cache_size = 64M tmp_table_size= 64M max_heap_table_size= 64M +slow_query_log = 1 +slow_query_log_file = /var/log/mysql/slow.log +long_query_time = 1 + +[client-server] +!includedir /etc/mysql/conf.d/ +!includedir /etc/mysql/mariadb.conf.d/ +[client] +default-character-set = utf8mb4 [mysqld] character_set_server = utf8mb4 collation_server = utf8mb4_general_ci -innodb_file_per_table=1 transaction_isolation = READ-COMMITTED binlog_format = ROW +innodb_large_prefix=on +innodb_file_format=barracuda +innodb_file_per_table=1 diff --git a/config/mariadb/init.sql b/config/mariadb/init.sql new file mode 100644 index 0000000..67d45e8 --- /dev/null +++ b/config/mariadb/init.sql @@ -0,0 +1,10 @@ +CREATE DATABASE IF NOT EXISTS postfix; +CREATE DATABASE IF NOT EXISTS nextcloud DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; + +CREATE USER IF NOT EXISTS 'selfhost'@'%' IDENTIFIED BY '123456'; + +GRANT ALL PRIVILEGES ON postfix.* TO 'selfhost'@'%' WITH GRANT OPTION; +GRANT ALL PRIVILEGES ON nextcloud.* TO 'selfhost'@'%' WITH GRANT OPTION; + +FLUSH PRIVILEGES; + diff --git a/config/nextcloud/x-fpm-overloads.conf b/config/nextcloud/x-fpm-overloads.conf deleted file mode 100644 index 0a290a5..0000000 --- a/config/nextcloud/x-fpm-overloads.conf +++ /dev/null @@ -1,7 +0,0 @@ -[www] -pm = dynamic -pm.max_children = 120 -pm.start_servers = 12 -pm.min_spare_servers = 6 -pm.max_spare_servers = 18 -pm.max_requests = 200 diff --git a/config/nextcloud/x-php-overloads.ini b/config/nextcloud/x-php-overloads.ini deleted file mode 100644 index 459f5e8..0000000 --- a/config/nextcloud/x-php-overloads.ini +++ /dev/null @@ -1,8 +0,0 @@ -[PHP] -opcache.enable=1 -opcache.interned_strings_buffer=8 -opcache.max_accelerated_files=10000 -opcache.memory_consumption=128 -opcache.save_comments=1 -opcache.revalidate_freq=1 -memory_limit = 512M diff --git a/docker-compose.yml b/docker-compose.yml index 55d2c45..78104cd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,28 +15,15 @@ services: - "4190:4190" # SIEVE STARTTLS - Optional - Recommended for mail filtering environment: - DBPASS=${DBPASS} + - DBUSER=${DBUSER} - RSPAMD_PASSWORD=${RSPAMD_PASSWORD} - ADD_DOMAINS=${ADD_DOMAINS} - ENABLE_POP3=${ENABLE_POP3} - DISABLE_RATELIMITING=${DISABLE_RATELIMITING} - RELAY_NETWORKS=${RELAY_NETWORKS} # Full list of options: https://github.com/hardware/mailserver#environment-variables - labels: - - "traefik.enable=true" - - "traefik.docker.network=proxy" - - "traefik.http.routers.spam.entrypoints=websecure" - - "traefik.http.routers.spam.rule=Host(`spam.${DOMAIN}`)" - - "traefik.http.routers.spam.service=spam" - - "traefik.http.routers.spam.tls=true" - - "traefik.http.routers.spam.tls.certresolver=letsencrypt" - - "traefik.http.routers.spam.tls.domains[0].main=mail.${DOMAIN}" - - "traefik.http.routers.spam.tls.domains[0].sans=spam.${DOMAIN}" - - "traefik.http.routers.spam.tls.options=default" - - "traefik.http.services.spam.loadbalancer.server.port=11334" - - "traefik.http.services.spam.loadbalancer.server.scheme=http" volumes: - ${DEPLOYMENT_PATH:-.}/volumes/mail:/var/mail - - ${DEPLOYMENT_PATH:-.}/volumes/traefik/acme:/etc/letsencrypt/acme - ${DEPLOYMENT_PATH:-.}/config/mail/dovecot/10-mail.conf:/etc/dovecot/conf.d/10-mail.conf - ${DEPLOYMENT_PATH:-.}/config/mail/dovecot/90-quota.conf:/etc/dovecot/conf.d/90-quota.conf - ${DEPLOYMENT_PATH:-.}/config/mail/dovecot/90-sieve.conf:/etc/dovecot/conf.d/90-sieve.conf @@ -58,8 +45,8 @@ services: - POSTFIXADMIN_SSH_PASSWORD=${POSTFIXADMIN_SSH_PASSWORD} - POSTFIXADMIN_DB_TYPE=mysqli - POSTFIXADMIN_DB_HOST=${DBHOST} - - POSTFIXADMIN_DB_USER=${PFDB_DB} - - POSTFIXADMIN_DB_NAME=${PFDB_USR} + - POSTFIXADMIN_DB_USER=${DBUSER} + - POSTFIXADMIN_DB_NAME=${PFDB_DB} - POSTFIXADMIN_DB_PASSWORD=${DBPASS} - POSTFIXADMIN_SMTP_SERVER=mail.${DOMAIN} - POSTFIXADMIN_SMTP_PORT=587 @@ -73,14 +60,14 @@ services: image: mariadb:11.7 restart: unless-stopped environment: - # Note: These variables are only used for the first start. Later changes are ignored. - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - MYSQL_DATABASE=${PFDB_DB} - - MYSQL_USER=${PFDB_USR} + - MYSQL_USER=${DBUSER} - MYSQL_PASSWORD=${DBPASS} volumes: - ${DEPLOYMENT_PATH:-.}/volumes/mysql/db/data:/var/lib/mysql - ${DEPLOYMENT_PATH:-.}/config/mariadb/:/etc/mysql/conf.d/:ro + - ${DEPLOYMENT_PATH:-.}/config/mariadb/init.sql:/docker-entrypoint-initdb.d/init.sql redis: image: redis:7.4-alpine @@ -88,7 +75,6 @@ services: command: redis-server --maxmemory 8G --maxmemory-policy allkeys-lru volumes: - ${DEPLOYMENT_PATH:-.}/volumes/redis/db:/data - - ${DEPLOYMENT_PATH:-.}/volumes/redis/tmp:/tmp/redis welcome: image: registry.gitlab.e.foundation/e/infra/docker-welcome:2.5.0 @@ -98,7 +84,7 @@ services: - IS_WELCOME=true - PFDB_HOST=${DBHOST} - PFDB_DB=${PFDB_DB} - - PFDB_USR=${PFDB_USR} + - PFDB_USR=${DBUSER} - PFDB_PW=${DBPASS} - POSTFIXADMIN_SSH_PASSWORD=${POSTFIXADMIN_SSH_PASSWORD} - WELCOME_SECRET_SHA=${WELCOME_SECRET_SHA} @@ -123,25 +109,32 @@ services: # - "mail.${DOMAIN}:${NC_HOST_IP}" nextcloud: - image: registry.gitlab.e.foundation/e/infra/ecloud/nextcloud/selfhost:26-0-8-23 + image: registry.gitlab.e.foundation/e/infra/ecloud/nextcloud/selfhost:selfhost-dynamic-conf restart: unless-stopped environment: - MYSQL_DATABASE=${MYSQL_DATABASE_NC} - - MYSQL_USER=${MYSQL_USER_NC} - - MYSQL_PASSWORD=${MYSQL_PASSWORD_NC} - - MYSQL_HOST={DBHOST} + - MYSQL_USER=${DBUSER} + - MYSQL_PASSWORD=${DBPASS} + - MYSQL_HOST=${DBHOST} + - POSTFIX_DATABASE=${PFDB_DB} + - REDIS_HOST=${REDIS_HOST} - NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER} - # below ENV disabled so NC container do not start install - # - NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD} - - OVERWRITEPROTOCOL=https + - NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD} + - NEXTCLOUD_TRUSTED_DOMAINS=${DOMAIN} - NEXTCLOUD_EMAIL_RECOVERY_APP_SECRET=${NEXTCLOUD_EMAIL_RECOVERY_APP_SECRET} + - WEBSITE_SECRET=${WEBSITE_SECRET} + - DOMAIN=${DOMAIN} + - SMTP_HOST=${SMTP_HOST} + - SMTP_SECURE=tls + - SMTP_PORT=587 + - SMTP_AUTHTYPE=PLAIN + - SMTP_NAME=drive@${DOMAIN} + - SMTP_PASSWORD=${SMTP_PW} + - MAIL_FROM_ADDRESS=drive + - MAIL_DOMAIN=${DOMAIN} + - WELCOME_SECRET=${WELCOME_SECRET} volumes: - - ${DEPLOYMENT_PATH:-.}/volumes/nextcloud/html:/var/www/html/ - - ${DEPLOYMENT_PATH:-.}/volumes/nextcloud/data:/var/www/data/ - - ${DEPLOYMENT_PATH:-.}/config/nextcloud/x-fpm-overloads.conf:/usr/local/etc/php-fpm.d/x-fpm-overloads.conf - - ${DEPLOYMENT_PATH:-.}/config/nextcloud/x-php-overloads.ini:/usr/local/etc/php/conf.d/x-php-overloads.ini - - ${DEPLOYMENT_PATH:-.}/volumes/nextcloud/log:/var/www/log/ - - ${DEPLOYMENT_PATH:-.}/volumes/redis/db:/tmp/redis + - ${DEPLOYMENT_PATH:-.}/volumes/nextcloud/html:/var/www/html depends_on: - mariadb - redis -- GitLab From e450773eb45923cd21468771a627fee77b4cf18b Mon Sep 17 00:00:00 2001 From: Nicolas Gelot Date: Fri, 4 Apr 2025 17:24:38 +0200 Subject: [PATCH 3/3] Update mariadb configuration --- .env.example | 5 +- config/mariadb/ecloud.cnf | 32 --- config/nginx/templates/default.conf.template | 205 +++++++++++-------- docker-compose.yml | 79 ++++--- 4 files changed, 175 insertions(+), 146 deletions(-) delete mode 100644 config/mariadb/ecloud.cnf diff --git a/.env.example b/.env.example index 4eb999c..ad2cc8a 100644 --- a/.env.example +++ b/.env.example @@ -36,9 +36,10 @@ WELCOME_SECRET=123456 WELCOME_SECRET_SHA=abcdefgh WEBSITE_SECRET=123456 ECLOUD_ACCOUNTS_SECRET=123456 +CREATE_ACCOUNT_PASSWORD=123456 # nextcloud +NEXTCLOUD_DOCKER_IMG=registry.gitlab.e.foundation/e/infra/ecloud/nextcloud/selfhost:selfhost-dynamic-conf NEXTCLOUD_ADMIN_USER=admin -NEXTCLOUD_ADMIN_PASSWORD=@adm1n +NEXTCLOUD_ADMIN_PASSWORD=@dm1n NEXTCLOUD_EMAIL_RECOVERY_APP_SECRET=123456 -CREATE_ACCOUNT_PASSWORD=123456 diff --git a/config/mariadb/ecloud.cnf b/config/mariadb/ecloud.cnf deleted file mode 100644 index f437fa8..0000000 --- a/config/mariadb/ecloud.cnf +++ /dev/null @@ -1,32 +0,0 @@ -[server] -skip_name_resolve = 1 -innodb_buffer_pool_size = 128M -innodb_buffer_pool_instances = 1 -innodb_flush_log_at_trx_commit = 2 -innodb_log_buffer_size = 32M -innodb_max_dirty_pages_pct = 90 -query_cache_type = 1 -query_cache_limit = 2M -query_cache_min_res_unit = 2k -query_cache_size = 64M -tmp_table_size= 64M -max_heap_table_size= 64M -slow_query_log = 1 -slow_query_log_file = /var/log/mysql/slow.log -long_query_time = 1 - -[client-server] -!includedir /etc/mysql/conf.d/ -!includedir /etc/mysql/mariadb.conf.d/ - -[client] -default-character-set = utf8mb4 - -[mysqld] -character_set_server = utf8mb4 -collation_server = utf8mb4_general_ci -transaction_isolation = READ-COMMITTED -binlog_format = ROW -innodb_large_prefix=on -innodb_file_format=barracuda -innodb_file_per_table=1 diff --git a/config/nginx/templates/default.conf.template b/config/nginx/templates/default.conf.template index 94202c7..8692ba3 100644 --- a/config/nginx/templates/default.conf.template +++ b/config/nginx/templates/default.conf.template @@ -1,3 +1,9 @@ +# Set the `immutable` cache control options only for assets with a cache busting `v` argument +map $arg_v $asset_immutable { + "" ""; +default ", immutable"; +} + upstream php-handler { server nextcloud:9000; } @@ -7,43 +13,23 @@ server { listen [::]:80; server_name ${DOMAIN}; - root /var/www/html; - - - include /etc/nginx/params/ssl_params; - # We include these headers directly because some are already set by Nextcloud. - #include /etc/nginx/params/headers_params; - add_header X-Content-Type-Options "nosniff" always; - add_header X-XSS-Protection "1; mode=block"; - add_header Strict-Transport-Security "max-age=15768000"; - add_header Referrer-Policy "no-referrer" always; - add_header X-Frame-Options "SAMEORIGIN" always; - add_header X-Robots-Tag "noindex,nofollow" always; - add_header X-Download-Options "noopen" always; - add_header X-Permitted-Cross-Domain-Policies "none" always; - fastcgi_hide_header X-Powered-By; - server_tokens off; - - location = /.well-known/carddav { - return 301 $scheme://$host/remote.php/dav; - } - location = /.well-known/caldav { - return 301 $scheme://$host/remote.php/dav; - } - - location = /.well-known/webfinger { - return 301 $scheme://$host/index.php$uri; - } - location = /.well-known/nodeinfo { - return 301 $scheme://$host/index.php$uri; - } - - client_max_body_size 4096M; + # 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; - fastcgi_connect_timeout 60; - fastcgi_send_timeout 600; - fastcgi_read_timeout 600; + # 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; # Enable gzip but do not remove ETag headers gzip on; @@ -51,75 +37,132 @@ server { gzip_comp_level 4; gzip_min_length 256; gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; - # Enable compression for JS/CSS/HTML bundle, for improved client load times. - # It might be nice to compress JSON, but leaving that out to protect against potential - # compression+encryption information leak attacks like BREACH. - gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject 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; + 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; - location / { - rewrite ^ /index.php; + # 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; + + # Path to the root of your installation + root /var/www/html; + + # 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`, `/ocm-provider`, `/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 ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ { - deny all; + location = /robots.txt { + allow all; + log_not_found off; + access_log off; } - location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { - deny all; + + # 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; } - location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|.+/richdocumentscode/proxy)\.php(?:$|/) { - fastcgi_split_path_info ^(.+?\.php)(/.*|)$; + # 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; - #Avoid sending the security headers twice - fastcgi_param modHeadersAvailable true; - fastcgi_param front_controller_active true; + #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; - } - location ~ ^/(?:updater|ocs-provider)(?:$|/) { - try_files $uri/ =404; - index index.php; + fastcgi_max_temp_file_size 0; } - # Adding the cache control header for js, css and map files - # Make sure it is BELOW the PHP block - location ~ \.(?:css|js|woff2?|svg|gif|map)$ { + # 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; add_header Cache-Control "public, max-age=15778463"; - # Add headers to serve security related headers (It is intended to - # have those duplicated to the ones above) - # Before enabling Strict-Transport-Security headers please read into - # this topic first. - #add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always; - # - # 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 Referrer-Policy "no-referrer" always; - add_header X-Content-Type-Options "nosniff" always; - add_header X-Download-Options "noopen" always; - add_header X-Frame-Options "SAMEORIGIN" always; - add_header X-Permitted-Cross-Domain-Policies "none" always; - add_header X-Robots-Tag "none" always; - add_header X-XSS-Protection "1; mode=block" always; - - # Optional: Don't log access to assets - access_log off; + 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 ~ \.wasm$ { + default_type application/wasm; + } } - location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$ { + location ~ \.(otf|woff2?)$ { try_files $uri /index.php$request_uri; - # Optional: Don't log access to other assets - access_log off; + 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 the Rainloop admin message saying "data folder accessible" diff --git a/docker-compose.yml b/docker-compose.yml index 78104cd..4cf9790 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,30 @@ services: + mariadb: + image: mariadb:11.7 + restart: unless-stopped + environment: + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} + - MYSQL_DATABASE=${PFDB_DB} + - MYSQL_USER=${DBUSER} + - MYSQL_PASSWORD=${DBPASS} + command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW + volumes: + - ${DEPLOYMENT_PATH:-.}/volumes/mysql/db/data:/var/lib/mysql + - ${DEPLOYMENT_PATH:-.}/config/mariadb/init.sql:/docker-entrypoint-initdb.d/init.sql + healthcheck: + test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] + start_period: 10s + interval: 10s + timeout: 5s + retries: 3 + + redis: + image: redis:7.4-alpine + restart: unless-stopped + command: redis-server --maxmemory 8G --maxmemory-policy allkeys-lru + volumes: + - ${DEPLOYMENT_PATH:-.}/volumes/redis/db:/data + mailserver: image: mailserver2/mailserver:1.1.22 domainname: ${DOMAIN} # Mail server A/MX/FQDN & reverse PTR = mail.${DOMAIN}. @@ -56,25 +82,20 @@ services: - mailserver - mariadb - mariadb: - image: mariadb:11.7 + mail-autodiscover-autoconfig: + image: wdes/mail-autodiscover-autoconfig:latest restart: unless-stopped environment: - - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - - MYSQL_DATABASE=${PFDB_DB} - - MYSQL_USER=${DBUSER} - - MYSQL_PASSWORD=${DBPASS} - volumes: - - ${DEPLOYMENT_PATH:-.}/volumes/mysql/db/data:/var/lib/mysql - - ${DEPLOYMENT_PATH:-.}/config/mariadb/:/etc/mysql/conf.d/:ro - - ${DEPLOYMENT_PATH:-.}/config/mariadb/init.sql:/docker-entrypoint-initdb.d/init.sql - - redis: - image: redis:7.4-alpine - restart: unless-stopped - command: redis-server --maxmemory 8G --maxmemory-policy allkeys-lru + ROCKET_PROFILE: production + ROCKET_ADDRESS: "0.0.0.0" + ROCKET_PORT: "80" + APPLE_MAIL_UUID: ${AUTODISCOVER_AM_UUID} + APPLE_PROFILE_UUID: ${AUTODISCOVER_AP_UUID} + IMAP_HOSTNAME: ${SMTP_HOST} + POP_HOSTNAME: ${SMTP_HOST} + SMTP_HOSTNAME: ${SMTP_HOST} volumes: - - ${DEPLOYMENT_PATH:-.}/volumes/redis/db:/data + - ${DEPLOYMENT_PATH:-.}/config/autodiscover/xml:/usr/lib/mail-autodiscover-autoconfig/templates/xml welcome: image: registry.gitlab.e.foundation/e/infra/docker-welcome:2.5.0 @@ -109,7 +130,7 @@ services: # - "mail.${DOMAIN}:${NC_HOST_IP}" nextcloud: - image: registry.gitlab.e.foundation/e/infra/ecloud/nextcloud/selfhost:selfhost-dynamic-conf + image: ${NEXTCLOUD_DOCKER_IMG} restart: unless-stopped environment: - MYSQL_DATABASE=${MYSQL_DATABASE_NC} @@ -136,23 +157,19 @@ services: volumes: - ${DEPLOYMENT_PATH:-.}/volumes/nextcloud/html:/var/www/html depends_on: - - mariadb - - redis + mariadb: + condition: service_healthy + redis: + condition: service_started - mail-autodiscover-autoconfig: - image: wdes/mail-autodiscover-autoconfig:latest + nextcloud-cron: + image: ${NEXTCLOUD_DOCKER_IMG} restart: unless-stopped - environment: - ROCKET_PROFILE: production - ROCKET_ADDRESS: "0.0.0.0" - ROCKET_PORT: "80" - APPLE_MAIL_UUID: ${AUTODISCOVER_AM_UUID} - APPLE_PROFILE_UUID: ${AUTODISCOVER_AP_UUID} - IMAP_HOSTNAME: ${SMTP_HOST} - POP_HOSTNAME: ${SMTP_HOST} - SMTP_HOSTNAME: ${SMTP_HOST} + entrypoint: /cron.sh volumes: - - ${DEPLOYMENT_PATH:-.}/config/autodiscover/xml:/usr/lib/mail-autodiscover-autoconfig/templates/xml + - ${DEPLOYMENT_PATH:-.}/volumes/nextcloud/html:/var/www/html + depends_on: + - nextcloud nginx: image: nginx:stable-alpine -- GitLab