1
0
mirror of https://github.com/mailcow/mailcow-dockerized.git synced 2026-06-14 18:40:23 +00:00

Compare commits

..

133 Commits

Author SHA1 Message Date
FreddleSpl0it a632980871 Merge pull request #6336 from mailcow/staging
Update 2025-02
2025-02-27 11:48:57 +01:00
DerLinkman 5296085189 update.sh: corrected typos inside update.sh 2025-02-27 11:47:08 +01:00
DerLinkman a4c2cf4c67 scripts: adapted new docker image names to docker_garbage function + removed dup 2025-02-27 11:44:52 +01:00
FreddleSpl0it 2d1ef41d32 Merge pull request #6335 from mailcow/staging
Update 2025-02
2025-02-27 11:05:55 +01:00
Peter 3c9d0c9d57 use ghcr.io for backupimage (#6333)
* use ghcr.io for backup image

* backup script: use renamed script + improved build of image

---------

Co-authored-by: DerLinkman <niklas.meyer@servercow.de>
2025-02-27 10:58:23 +01:00
FreddleSpl0it 35a6f81d0d [Redis] use 7.4.2-alpine image 2025-02-27 09:28:52 +01:00
FreddleSpl0it 4b31c04e3e Merge pull request #6330 from mailcow/feat/major-update-prompt
Prompt user before applying major updates
2025-02-27 08:15:21 +01:00
FreddleSpl0it 3d9cc2f6dd add 2025-02 to major versions 2025-02-27 08:14:34 +01:00
DerLinkman 704dd50262 compose: use ghcr.io for new/current mailcow docker images instead of docker hub (#6332) 2025-02-26 15:20:57 +01:00
FreddleSpl0it c4a0e370b7 Merge pull request #6155 from PseudoResonance/fix2752
Fix #2752 - Allow domain recipients for address rewrite
2025-02-26 10:01:03 +01:00
FreddleSpl0it 787fa49d0c prompt user before applying major updates 2025-02-25 12:08:21 +01:00
DerLinkman a6c38590ca rspamd: upgraded rspamd to 3.11.0-2 (incl. NIXSPAM Removal) (#6328) 2025-02-25 09:23:10 +01:00
PseudoResonance e52323bf1d Fix @ prefixing domain rewrite and update localization 2025-02-24 22:36:17 -08:00
PseudoResonance f15ee39b63 Fix #2752: Domain recipient for address rewrite
(cherry picked from commit 40f6d691d8774d6f813153974f8fe462a8db9ab3)
2025-02-24 22:07:23 -08:00
FreddleSpl0it 6ec5e88793 Merge pull request #6309 from mailcow/fix/6308
[Dovecot][Netfilter] Fix dovecot failed login regex
2025-02-24 11:26:06 +01:00
FreddleSpl0it 7d35646342 [Netfilter] adjust dovecot failed login regex 2025-02-24 09:20:41 +01:00
FreddleSpl0it 321965adee [Netfilter] Fix dovecot password mismatch regex 2025-02-18 15:05:59 +01:00
Peter 7bce5d836b Move sed cmd to remove discontinued DNSBLs (#6315)
* Move sed cmd to remove discontinued DNSBLs

* compose: bump postfix version

---------

Co-authored-by: DerLinkman <niklas.meyer@servercow.de>
2025-02-18 11:20:03 +01:00
FreddleSpl0it 351f4ce787 [Redis] Add support for masterauth via env var 2025-02-18 11:16:06 +01:00
FreddleSpl0it a567d5dc31 [Nginx] Add support for trusted proxies via env var 2025-02-18 11:03:34 +01:00
DerLinkman 4ac541f671 [Mariadb] Update to 10.11 (LTS) (#5152)
* [Mariadb] Update to 10.11 (LTS)

* mysql: set default collation to general_ci
2025-02-17 15:48:25 +01:00
Dmitriy Alekseev f6dc0b463f Update Rspamd to 3.11.0 and enable SMTPUTF8 for outgoing mail (#6216)
* Update Rspamd to 3.11

* Enable SMTPUTF8 and hide it from SMTPD greeting

* Update options.inc

* compose: increased rspamd tag
2025-02-17 14:41:39 +01:00
DerLinkman 16e22e23dc sogo: switched apt source to sogo again (supports aarch64 now) 2025-02-17 14:31:50 +01:00
FreddleSpl0it d8afa6f393 [Dovecot][Netfilter] Fix dovecot failed login regex 2025-02-14 13:12:12 +01:00
milkmaker 836e3f15b7 [Web] Updated lang.es-es.json (#6307)
Co-authored-by: Julie GINESTIERE <julien.ginestiere+git@gmail.com>
2025-02-13 19:32:39 +01:00
FreddleSpl0it aaa7e4a184 [Web] Fix incorrect session lifetime in sogo-auth.php 2025-02-13 11:54:55 +01:00
FreddleSpl0it 3912341b32 [SOGo] rename custom logo 2025-02-12 11:31:14 +01:00
FreddleSpl0it 735d5f0e56 Merge pull request #6220 from Babybatrick/staging
Adding lines to docker-compose.yml to allow for simpler SOGo web client UI customisation
2025-02-12 10:54:16 +01:00
FreddleSpl0it f375794fb7 Merge pull request #6223 from mailcow/ffdhe2048
Ffdhe2048
2025-02-12 10:48:22 +01:00
renovate[bot] 4ed3017a02 chore(deps): update devops-infra/action-pull-request action to v0.6.0 (#6302) 2025-02-12 06:56:10 +01:00
FreddleSpl0it ef2f5f7be0 [Dovecot] Use Redis ACL user quota_notify with restricted access 2025-02-11 16:59:18 +01:00
Henry Williams 743e88fd67 Update generate_config.sh version checking for wider compatibility (#6270)
* Update generate_config.sh version checking for wider compatibility 

fix: replace `grep -oP` with `grep -oE` for broader compatibility

The `-P` option (Perl-compatible regex) is not supported in all versions of `grep`, particularly the default BSD `grep` on macOS. This change replaces `-P` with `-E` (extended regex), which is more widely available and ensures compatibility across different environments.

Tested on macOS and Linux.

* Update generate_config.sh to remove use of platform dependent grep

Replaced version checking using free-form text. Instead, uses Docker’s built-in templating instead of parsing free-form text. This gives cross-platform consistency without dependency on particular versions of grep.
2025-02-11 13:55:03 +01:00
DerLinkman ac2f0c7db1 Merge pull request #6286 from mailcow/fix-workflow-staging
Fix check_prs_if_on_staging workflow
2025-02-11 13:52:44 +01:00
FreddleSpl0it 120366fec7 Merge pull request #6291 from mailcow/staging
Update 2025-01a
2025-02-04 13:55:30 +01:00
FreddleSpl0it 3544a2246e [Nginx] fix ADDITIONAL_SERVER_NAMES array 2025-02-04 13:30:00 +01:00
FreddleSpl0it 97890b71f1 [Nginx] Invert SKIP container condition 2025-02-03 12:22:13 +01:00
FreddleSpl0it e645f931dc [Nginx] Add env var for HTTP to HTTPS redirection 2025-02-03 12:05:08 +01:00
FreddleSpl0it bbdec0960a Merge pull request #6290 from mailcow/fix/nginx-vhosts
[Nginx] Use vhosts for additional server names
2025-02-03 11:35:09 +01:00
milkmaker 41ba7d97fa update postscreen_access.cidr (#6287) 2025-02-01 17:06:07 +01:00
Peter 83fc2c6387 It's github-token now 2025-01-31 17:20:28 +01:00
DerLinkman aac4c6b5f4 postfix: added master.pid removal and startsecs to supervisord (#6284) 2025-01-31 12:49:39 +01:00
FreddleSpl0it 3c0f775e2f Merge pull request #6281 from mailcow/fix/6275
[Nginx] Fix
2025-01-31 10:49:21 +01:00
FreddleSpl0it 3a81b84cf7 [Nginx] Fix #6275 2025-01-30 14:49:18 +01:00
FreddleSpl0it a2e87e0880 [Web] Add validation for server_name against allow list 2025-01-30 11:47:55 +01:00
DerLinkman 2407aa7895 Merge branch 'feat/clamd-rebuild' into staging 2025-01-29 14:01:39 +01:00
DerLinkman 244d4b8c4c compose: rollback clamd version until next major... accidentally pushed 2025-01-29 13:46:53 +01:00
FreddleSpl0it 0ad327bbe5 [Nginx] Use separate vhosts for additional server names 2025-01-29 09:51:45 +01:00
DerLinkman f92ddd86c5 clamd: update to 1.4.2 + build from source instead using alpine packages (#6273)
* clamd: update to 1.4.2 + build from source instead using alpine packages

* clamd: remove exposed ports from buildfile

* clamd: cleanup dockerfile
2025-01-29 09:49:04 +01:00
DerLinkman 1a087bb2c8 clamd: cleanup dockerfile 2025-01-28 14:49:11 +01:00
DerLinkman 65bc581fab clamd: remove exposed ports from buildfile 2025-01-28 14:36:43 +01:00
DerLinkman 60a2270d1e clamd: update to 1.4.2 + build from source instead using alpine packages 2025-01-28 14:25:56 +01:00
FreddleSpl0it 8ed51e500f Merge pull request #6260 from mailcow/manitu
Remove discontinued Nixspam DNSBL
2025-01-27 16:21:29 +01:00
FreddleSpl0it 45d14254f2 [Postfix] Remove discontinued Nixspam DNSBL from existing dns_blocklists.cf 2025-01-24 10:06:50 +01:00
Michael Kuron 04116982a5 Remove discontinued Nixspam DNSBL 2025-01-23 22:16:54 +01:00
FreddleSpl0it ba0349a911 Merge pull request #6256 from mailcow/staging
[Nginx] move conf.d include to end of nginx.conf
2025-01-23 14:55:38 +01:00
FreddleSpl0it 04058ab06e [Nginx] move conf.d include to end of nginx.conf 2025-01-23 14:54:28 +01:00
FreddleSpl0it 8caf09cd80 Merge pull request #6253 from mailcow/staging
2025-01
2025-01-23 12:01:38 +01:00
FreddleSpl0it da02e26172 [Web] Delete old session_id after regenerate 2025-01-23 11:59:01 +01:00
DerLinkman 43f945fe01 dovecot: fix index timeout seconds 2025-01-23 11:51:41 +01:00
DerLinkman e76c0ba9a6 Merge branch 'staging' 2025-01-23 11:31:01 +01:00
DerLinkman d83111568e update.sh: remove accidentally added exit at end of solr volume removal 2025-01-23 11:30:05 +01:00
FreddleSpl0it 1b578caabb Merge pull request #6251 from mailcow/staging
2025-01
2025-01-23 11:16:38 +01:00
DerLinkman 1dac8f1f66 scripts: changed SKIP_FTS text to warn on lower threaded systems 2025-01-23 08:42:22 +01:00
DerLinkman 5a04942d89 update.sh: changed SKIP_FTS default to y instead n for updates 2025-01-23 08:38:14 +01:00
DerLinkman a30f6696a3 update.sh: fixed --force for solr-removal + code optimization 2025-01-23 08:30:48 +01:00
FreddleSpl0it 1fca328266 [Nginx] Disable IPv6 listener for Rspamd dynmaps when DISABLE_IPv6=y 2025-01-22 15:11:46 +01:00
FreddleSpl0it 7bcd61ecb5 [Nginx] Generate includes for custom configs 2025-01-22 14:30:47 +01:00
renovate[bot] ee7a8624fc chore(deps): update actions/stale action to v9.1.0 (#6247)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-21 06:38:13 +01:00
DerLinkman 4708b1398b update.sh: fix mailcow fts update versioning 2025-01-20 15:41:48 +01:00
DerLinkman 746915cbdd fts: change autoindex to occur on mailboxes of receiving 20 or more mails daily 2025-01-20 14:21:15 +01:00
Alyx 36db68677c Reduce sa rules download retry limit to 5 (#6225)
Reduces the retry limit for the sa rules download to a more reasonable 5 retries to prevent running in a timeout condition.
2025-01-20 14:10:29 +01:00
gwelch-contegix 08599c1960 Fix community support url (#6245) 2025-01-20 14:09:31 +01:00
DerLinkman 31e001ebee flatcurve: change default amount of processes to 1 2025-01-16 11:37:15 +01:00
FreddleSpl0it 8fea9fc21f Merge pull request #6211 from jan-oratowski/patch-1
Fix missing property in Create Sync Job request
2025-01-14 12:18:29 +01:00
FreddleSpl0it 2f1884e94b Merge pull request #6205 from PhoenixPeca/master
Improve the existing validation flow for sieve filter
2025-01-14 12:08:56 +01:00
FreddleSpl0it 24b3d8f850 Merge pull request #6001 from marekfilip/feat/temp-email-aliases
add temporary email description
2025-01-14 11:52:44 +01:00
FreddleSpl0it d280025b51 [Web] Regenerate session_id on successful login 2025-01-14 11:30:41 +01:00
FreddleSpl0it abd789f629 [Web] Escape mailbox name before querying aliases 2025-01-14 11:18:20 +01:00
milkmaker 69f6a82905 [Web] Updated lang.fr-fr.json (#6238)
Co-authored-by: Neuronnexion <support@nnx.com>
2025-01-09 06:51:42 +01:00
milkmaker 10328981b6 Translations update from Weblate (#6235)
* [Web] Updated lang.fr-fr.json

Co-authored-by: Neuronnexion <support@nnx.com>

* [Web] Updated lang.zh-cn.json

Co-authored-by: Easton Man <me@eastonman.com>

---------

Co-authored-by: Neuronnexion <support@nnx.com>
Co-authored-by: Easton Man <me@eastonman.com>
2025-01-05 15:25:45 +01:00
Filip Marek 150b2bbd9d Merge branch 'mailcow:master' into feat/temp-email-aliases 2025-01-03 11:40:01 +01:00
milkmaker 40a8bc808a update postscreen_access.cidr (#6232) 2025-01-01 03:26:18 +01:00
Dmitriy Alekseev d92aa4b15d Update dhparams.pem
Use https://ssl-config.mozilla.org/ffdhe2048.txt due to better security of the key
2024-12-20 15:39:41 +01:00
milkmaker 2d2dacb70e [Web] Updated lang.fr-fr.json (#6221)
[Web] Updated lang.fr-fr.json

Co-authored-by: Neuronnexion <support@nnx.com>
Co-authored-by: Peter <magic@kthx.at>
2024-12-19 17:10:43 +01:00
Amin ade20d79d4 Uploading of the necessary files, after new volumes were added to docker-compose.yml (sogo-mailcow container)
After new volumes were added to docker-compose.yml in the sogo-mailcow container, it is necessary to include the specified files in the path, in order for docker to correctly start after running `docker compose up` command, otherwise error will appear, as necessary files would be missing.
The files uploaded are original SOGo UI elements, obtained from the sogo-mailcow container. Whenever users will need to change the UI elements, they would just need to change these files. Hence simplifying the process.
2024-12-19 22:13:27 +08:00
Amin 65bc8f0972 Update docker-compose.yml (sogo-mailcow)
This commit includes the addition of 3 lines, in the volumes part of the sogo-mailcow container, to allow for better customisation of the user interface on the web client page.
2024-12-19 21:59:05 +08:00
Jan Oratowski c6f6eda0bf Fix missing property in Create Sync Job request
In example there was property called "user1", but it was missing from request definition.

This resulted in nswagger generating incorrect C# API code.
2024-12-14 15:27:37 +01:00
milkmaker 357a4d7fb3 [Web] Updated lang.fr-fr.json (#6209)
Co-authored-by: Neuronnexion <support@nnx.com>
2024-12-13 12:21:12 +01:00
DerLinkman 1c6684a539 compose: fix dovecot tagging 2024-12-12 17:02:21 +01:00
DerLinkman de80c120c9 update.sh: added silent fix for removing old fts.conf in order to update properly 2024-12-12 16:57:32 +01:00
Niklas Meyer 3e8bb06a37 dovecot: replace solr fts with flatcurve (xapian) (#5680)
* fts-flatcurve: inital implementation

* fts: removed solr from compose.yml

* flatcurve: added heap and proc logic to dovecot

* added logic for update.sh & generate for Flatcurve

* delete old iteration of fts-flatcurve.conf

* updated default fts.conf

* updated .gitignore to exclude fts.conf for further git updates

* Remove autogeneration of fts.conf (disable override)

* cleanup all left solr stuff

* renamed SKIP_FLATCURVE to SKIP_FTS

* cleanup leftovers solr in lang files

* moved lazy_expunge plugin only to mail_plugins

* added fts timeout value

* compose: remove dev image of dovecot

* updated japanese translation
2024-12-12 16:44:42 +01:00
milkmaker b087ac9e27 Translations update from Weblate (#6206)
* [Web] Updated lang.fr-fr.json

Co-authored-by: Neuronnexion <support@nnx.com>

* [Web] Updated lang.si-si.json

Co-authored-by: Matjaž Tekavec <matjaz@moj-svet.si>

---------

Co-authored-by: Neuronnexion <support@nnx.com>
Co-authored-by: Matjaž Tekavec <matjaz@moj-svet.si>
2024-12-11 18:10:51 +01:00
Phoenix Eve Aspacio d09e4ff020 Convert AJAX to POST request
This AJAX request sends form data in $_GET request query. This is problematic and unreliable when validating superrrr loooooong conditions, especially in environments that use reverse-proxy.

Been having this problem and this PR solves it. :)
2024-12-11 10:06:10 +08:00
Phoenix Eve Aspacio f065842402 Updated to $_REQUEST.
tested from my end.
2024-12-11 10:03:47 +08:00
Niklas Meyer 3875e8377a sogo: added SOGoDisableOrganizerEventCheck value to sogo.conf (#6204) 2024-12-10 15:59:02 +01:00
Christian 🦄 7c8e5c10ca Add create command to prevent external: true warnings (#6203)
This is related to https://github.com/mailcow/mailcow-dockerized/issues/5970 and https://community.mailcow.email/d/2126-backup-restore/2

It adds `docker compose create` to the script which gets executed directly after the sync of the mailcow-dockerized directory. This way the Docker daemon on the remote side creates everything and we get rid of the warning "volume "XYZ" already exists but was not created by Docker Compose. Use `external: true` to use an existing volume"

This is helpful if you use the create-cold-standby.sh script to migrate your mailcow installation to another server and don't want to get those warnings after migration.

Co-authored-by: Niklas Meyer <niklas.meyer@servercow.de>
2024-12-10 09:25:29 +01:00
Filip Marek 1a8e1a2677 add escape html for description 2024-12-09 23:07:43 +01:00
Filip Marek 0d635e2658 increase migrations verion 2024-12-09 23:07:43 +01:00
Filip Marek 60ca25026d add temporary email description 2024-12-09 23:07:02 +01:00
Peter ed2837edd8 Remove legacy Nextcloud settings (#6050) 2024-12-09 13:49:24 +01:00
FreddleSpl0it fa3b789fbb [Web] fix issue #6185 2024-12-09 13:07:00 +01:00
FreddleSpl0it 49e05f5120 [Web] fix oauth2 redirect after login 2024-12-09 11:36:05 +01:00
FreddleSpl0it 24453993f3 Merge pull request #6186 from h3ssan/feat/search-mailbox-by-full-name
Implement search mailboxes by fullname
2024-12-09 10:21:39 +01:00
FreddleSpl0it 8853e2c44a [Nginx] Use SOGo IPv4 for upstream 2024-12-09 09:50:16 +01:00
Tatsuya Yokota d1af52b4e7 Add initial Japanese language files (#6198)
* Add initial Japanese language files

* Reordered language list: moved Japanese (日本語) below Italian (Italiano)

---------

Co-authored-by: Tatsuya Yokota <git@acoustype.com>
2024-12-06 09:44:16 +01:00
i-curve 6e8e13cebc fix: check docker version fail in generate_config.sh #6187 (#6188)
close #6187

Signed-off-by: i-curve <i-curve@qq.com>
Co-authored-by: Niklas Meyer <niklas.meyer@servercow.de>
2024-12-04 12:28:14 +01:00
milkmaker f3060b37a6 update postscreen_access.cidr (#6189) 2024-12-01 17:49:28 +01:00
milkmaker 59c68f2603 Translations update from Weblate (#6190) 2024-12-01 17:49:10 +01:00
Hassan A Hashim 31185e3de1 Implement search mailboxes by fullname 2024-11-27 14:47:57 +03:00
Habetdin 4dbfd3abad Update lang.ru-ru.json (#6184) 2024-11-25 16:01:17 +01:00
FreddleSpl0it b4e6002bcf Merge pull request #6076 from Habetdin/staging
Only show active protocols on "last login" in mailbox overview
2024-11-21 10:24:41 +01:00
FreddleSpl0it 6af907cff0 Merge pull request #6182 from mailcow/fix/4518
[Web] allow dots in dkim selectors
2024-11-20 13:11:34 +01:00
FreddleSpl0it ba282233ea [Web] allow dots in dkim selectors 2024-11-20 13:05:02 +01:00
FreddleSpl0it 6f4c2b3361 Merge pull request #6181 from mailcow/fix/5703
[Web] Add additional columns to _sogo_static_view
2024-11-20 11:15:35 +01:00
FreddleSpl0it d08b9aec32 [Web] Add additional columns to _sogo_static_view 2024-11-20 11:09:49 +01:00
FreddleSpl0it bb310600b2 Merge pull request #6180 from mailcow/fix/6046
[Web] add missing translation for ratelimit in templates overview
2024-11-20 10:02:34 +01:00
FreddleSpl0it fe7211f27f [Web] add missing translation for ratelimit in templates overview 2024-11-20 09:57:14 +01:00
FreddleSpl0it 8e9a9364a8 Merge pull request #6146 from mailcow/feat/redis-pw
Enable password protection for Redis
2024-11-19 15:32:36 +01:00
FreddleSpl0it 6831f94fdb [Redis] redis-cli suppress auth warning 2024-11-19 15:10:52 +01:00
FreddleSpl0it b0de756a7c [Redis] Rename docker-entrypoint.sh to redis-conf.sh 2024-11-19 14:54:36 +01:00
FreddleSpl0it 922f8777b0 Merge pull request #6168 from mailcow/fix/f2b-banlist
[Web] remove f2b banlist from json_api.php
2024-11-19 14:32:31 +01:00
FreddleSpl0it c1903f121d [Redis] set password via docker-entrypoint.sh 2024-11-19 14:25:31 +01:00
FreddleSpl0it 89fb1322c6 Enable password protection for Redis 2024-11-19 14:25:31 +01:00
FreddleSpl0it 852d944cfb [Web] remove f2b banlist from json_api.php 2024-11-19 14:13:37 +01:00
Niklas Meyer bca4e1a03d update.sh: precaution ask for deletion of dns_blocklists.cf if old format (#6154) 2024-11-19 14:13:37 +01:00
FreddleSpl0it 326a446f8b Merge pull request #6177 from mailcow/feat/jinja2-nginx
[Nginx] Use jinja2 for templating nginx configuration
2024-11-19 14:08:37 +01:00
FreddleSpl0it 70ca5fde95 [Nginx] Use jinja2 for templating nginx configuration 2024-11-19 08:39:52 +01:00
DerLinkman 5ad4ab5b60 update.sh: fixed typos 2024-11-15 16:39:06 +01:00
Niklas Meyer bd9f4ba0a5 Merge pull request #6173 from mailcow/staging
2024-11b
2024-11-15 16:21:17 +01:00
DerLinkman d10d64dd92 mysql: increased thread_stack to 192k since 10.5.27 2024-11-15 16:18:22 +01:00
FreddleSpl0it 6d1f7482ed [Web] broadcast maildir move to dovecot containers on mailbox_rename 2024-11-15 16:18:21 +01:00
FreddleSpl0it b9f52df3f1 [Web] update _sogo_static_view on password reset 2024-11-15 16:18:21 +01:00
Habetdin 6550f0a3e8 Only show active protocols on "last login" in mailbox overview 2024-11-11 12:44:05 +03:00
141 changed files with 3588 additions and 2288 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
blank_issues_enabled: false blank_issues_enabled: false
contact_links: contact_links:
- name: ❓ Community-driven support (Free) - name: ❓ Community-driven support (Free)
url: https://docs.mailcow.email/#get-support url: https://docs.mailcow.email/#community-support-and-chat
about: Please use the community forum for questions or assistance about: Please use the community forum for questions or assistance
- name: 🔥 Premium Support (Paid) - name: 🔥 Premium Support (Paid)
url: https://www.servercow.de/mailcow?lang=en#support url: https://www.servercow.de/mailcow?lang=en#support
-6
View File
@@ -15,12 +15,6 @@
"data\/web\/inc\/lib\/vendor\/**" "data\/web\/inc\/lib\/vendor\/**"
], ],
"regexManagers": [ "regexManagers": [
{
"fileMatch": ["^helper-scripts\/nextcloud.sh$"],
"matchStrings": [
"#\\srenovate:\\sdatasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?( extractVersion=(?<extractVersion>.*?))?\\s.*?_VERSION=(?<currentValue>.*)"
]
},
{ {
"fileMatch": ["(^|/)Dockerfile[^/]*$"], "fileMatch": ["(^|/)Dockerfile[^/]*$"],
"matchStrings": [ "matchStrings": [
@@ -12,7 +12,7 @@ jobs:
- name: Send message - name: Send message
uses: thollander/actions-comment-pull-request@v3.0.1 uses: thollander/actions-comment-pull-request@v3.0.1
with: with:
GITHUB_TOKEN: ${{ secrets.CHECKIFPRISSTAGING_ACTION_PAT }} github-token: ${{ secrets.CHECKIFPRISSTAGING_ACTION_PAT }}
message: | message: |
Thanks for contributing! Thanks for contributing!
@@ -14,7 +14,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- name: Mark/Close Stale Issues and Pull Requests 🗑️ - name: Mark/Close Stale Issues and Pull Requests 🗑️
uses: actions/stale@v9.0.0 uses: actions/stale@v9.1.0
with: with:
repo-token: ${{ secrets.STALE_ACTION_PAT }} repo-token: ${{ secrets.STALE_ACTION_PAT }}
days-before-stale: 60 days-before-stale: 60
-1
View File
@@ -23,7 +23,6 @@ jobs:
- "postfix-mailcow" - "postfix-mailcow"
- "rspamd-mailcow" - "rspamd-mailcow"
- "sogo-mailcow" - "sogo-mailcow"
- "solr-mailcow"
- "unbound-mailcow" - "unbound-mailcow"
- "watchdog-mailcow" - "watchdog-mailcow"
runs-on: ubuntu-latest runs-on: ubuntu-latest
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Run the Action - name: Run the Action
uses: devops-infra/action-pull-request@v0.5.5 uses: devops-infra/action-pull-request@v0.6.0
with: with:
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }} github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}} title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}
+9 -5
View File
@@ -9,6 +9,8 @@ on:
jobs: jobs:
docker_image_build: docker_image_build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
packages: write
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -19,17 +21,19 @@ jobs:
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub - name: Login to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
username: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_USERNAME }} registry: ghcr.io
password: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_TOKEN }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push - name: Build and push
uses: docker/build-push-action@v6 uses: docker/build-push-action@v5
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
file: data/Dockerfiles/backup/Dockerfile file: data/Dockerfiles/backup/Dockerfile
push: true push: true
tags: mailcow/backup:latest tags: ghcr.io/mailcow/backup:latest
+4 -1
View File
@@ -23,6 +23,7 @@ data/conf/dovecot/sni.conf
data/conf/dovecot/sogo-sso.conf data/conf/dovecot/sogo-sso.conf
data/conf/dovecot/sogo_trusted_ip.conf data/conf/dovecot/sogo_trusted_ip.conf
data/conf/dovecot/sql data/conf/dovecot/sql
data/conf/dovecot/conf.d/fts.conf
data/conf/nextcloud-*.bak data/conf/nextcloud-*.bak
data/conf/nginx/*.active data/conf/nginx/*.active
data/conf/nginx/*.bak data/conf/nginx/*.bak
@@ -46,7 +47,9 @@ data/conf/sogo/custom-theme.js
data/conf/sogo/plist_ldap data/conf/sogo/plist_ldap
data/conf/sogo/sieve.creds data/conf/sogo/sieve.creds
data/conf/sogo/cron.creds data/conf/sogo/cron.creds
data/conf/sogo/sogo-full.svg data/conf/sogo/custom-fulllogo.svg
data/conf/sogo/custom-shortlogo.svg
data/conf/sogo/custom-fulllogo.png
data/gitea/ data/gitea/
data/gogs/ data/gogs/
data/hooks/dovecot/* data/hooks/dovecot/*
+2 -2
View File
@@ -4,9 +4,9 @@ exec 5>&1
# Do not attempt to write to slave # Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
export REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}" export REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
else else
export REDIS_CMDLINE="redis-cli -h redis -p 6379" export REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
fi fi
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
+1 -1
View File
@@ -124,7 +124,7 @@ case "$SUCCESS" in
;; ;;
*) # non-zero is non-fun *) # non-zero is non-fun
log_f "Failed to obtain certificate ${CERT} for domains '${CERT_DOMAINS[*]}'" log_f "Failed to obtain certificate ${CERT} for domains '${CERT_DOMAINS[*]}'"
redis-cli -h redis SET ACME_FAIL_TIME "$(date +%s)" redis-cli -h redis -a ${REDISPASS} --no-auth-warning SET ACME_FAIL_TIME "$(date +%s)"
exit 100${SUCCESS} exit 100${SUCCESS}
;; ;;
esac esac
+1 -1
View File
@@ -1,3 +1,3 @@
FROM debian:bookworm-slim FROM debian:bookworm-slim
RUN apt update && apt install pigz RUN apt update && apt install pigz -y --no-install-recommends
+91 -6
View File
@@ -1,14 +1,99 @@
FROM alpine:3.20 FROM alpine:3.21 AS builder
WORKDIR /src
ENV CLAMD_VERSION=1.4.2
RUN apk upgrade --no-cache \
&& apk add --update --no-cache \
g++ \
gcc \
gdb \
make \
cmake \
py3-pytest \
python3 \
valgrind \
bzip2-dev \
check-dev \
curl-dev \
json-c-dev \
libmilter-dev \
libxml2-dev \
linux-headers \
ncurses-dev \
openssl-dev \
pcre2-dev \
zlib-dev \
cargo \
rust
RUN wget -P /src https://www.clamav.net/downloads/production/clamav-${CLAMD_VERSION}.tar.gz \
&& tar xzfv /src/clamav-${CLAMD_VERSION}.tar.gz \
&& cd /src/clamav-${CLAMD_VERSION} \
&& cmake . \
-D CMAKE_BUILD_TYPE="Release" \
-D CMAKE_INSTALL_PREFIX="/usr" \
-D CMAKE_INSTALL_LIBDIR="/usr/lib" \
-D APP_CONFIG_DIRECTORY="/etc/clamav" \
-D DATABASE_DIRECTORY="/var/lib/clamav" \
-D ENABLE_CLAMONACC=OFF \
-D ENABLE_EXAMPLES=OFF \
-D ENABLE_MILTER=ON \
-D ENABLE_MAN_PAGES=OFF \
-D ENABLE_STATIC_LIB=OFF \
-D ENABLE_JSON_SHARED=ON \
&& cmake --build . \
&& make DESTDIR="/clamav" -j$(($(nproc) - 1)) install \
&& rm -r "/clamav/usr/lib/pkgconfig/" \
&& sed -e "s|^\(Example\)|\# \1|" \
-e "s|.*\(LocalSocket\) .*|\1 /tmp/clamd.sock|" \
-e "s|.*\(TCPSocket\) .*|\1 3310|" \
-e "s|.*\(TCPAddr\) .*|#\1 0.0.0.0|" \
-e "s|.*\(User\) .*|\1 clamav|" \
-e "s|^\#\(LogFile\) .*|\1 /var/log/clamav/clamd.log|" \
-e "s|^\#\(LogTime\).*|\1 yes|" \
"/clamav/etc/clamav/clamd.conf.sample" > "/clamav/etc/clamav/clamd.conf" \
&& sed -e "s|^\(Example\)|\# \1|" \
-e "s|.*\(DatabaseOwner\) .*|\1 clamav|" \
-e "s|^\#\(UpdateLogFile\) .*|\1 /var/log/clamav/freshclam.log|" \
-e "s|^\#\(NotifyClamd\).*|\1 /etc/clamav/clamd.conf|" \
-e "s|^\#\(ScriptedUpdates\).*|\1 yes|" \
"/clamav/etc/clamav/freshclam.conf.sample" > "/clamav/etc/clamav/freshclam.conf" \
&& sed -e "s|^\(Example\)|\# \1|" \
-e "s|.*\(MilterSocket\) .*|\1 inet:7357|" \
-e "s|.*\(User\) .*|\1 clamav|" \
-e "s|^\#\(LogFile\) .*|\1 /var/log/clamav/milter.log|" \
-e "s|^\#\(LogTime\).*|\1 yes|" \
-e "s|.*\(\ClamdSocket\) .*|\1 unix:/tmp/clamd.sock|" \
"/clamav/etc/clamav/clamav-milter.conf.sample" > "/clamav/etc/clamav/clamav-milter.conf" || exit 1
FROM alpine:3.21
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>" LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
RUN apk upgrade --no-cache \ RUN apk upgrade --no-cache \
&& apk add --update --no-cache \ && apk add --update --no-cache \
rsync \ tzdata \
clamav \ rsync \
bind-tools \ bind-tools \
bash \ bash \
tini tini \
json-c \
libbz2 \
libcurl \
libmilter \
libxml2 \
ncurses-libs \
pcre2 \
zlib \
libgcc \
&& addgroup -S "clamav" && \
adduser -D -G "clamav" -h "/var/lib/clamav" -s "/bin/false" -S "clamav" && \
install -d -m 755 -g "clamav" -o "clamav" "/var/log/clamav" && \
chown -R clamav:clamav /var/lib/clamav
COPY --from=builder "/clamav" "/"
# init # init
COPY clamd.sh /clamd.sh COPY clamd.sh /clamd.sh
+1
View File
@@ -91,6 +91,7 @@ done
) & ) &
BACKGROUND_TASKS+=($!) BACKGROUND_TASKS+=($!)
echo "$(clamd -V) is starting... please wait a moment."
nice -n10 clamd & nice -n10 clamd &
BACKGROUND_TASKS+=($!) BACKGROUND_TASKS+=($!)
+2 -2
View File
@@ -34,9 +34,9 @@ async def lifespan(app: FastAPI):
# Init redis client # Init redis client
if os.environ['REDIS_SLAVEOF_IP'] != "": if os.environ['REDIS_SLAVEOF_IP'] != "":
redis_client = redis = await aioredis.from_url(f"redis://{os.environ['REDIS_SLAVEOF_IP']}:{os.environ['REDIS_SLAVEOF_PORT']}/0") redis_client = redis = await aioredis.from_url(f"redis://{os.environ['REDIS_SLAVEOF_IP']}:{os.environ['REDIS_SLAVEOF_PORT']}/0", password=os.environ['REDISPASS'])
else: else:
redis_client = redis = await aioredis.from_url("redis://redis-mailcow:6379/0") redis_client = redis = await aioredis.from_url("redis://redis-mailcow:6379/0", password=os.environ['REDISPASS'])
# Init docker clients # Init docker clients
sync_docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock', version='auto') sync_docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock', version='auto')
-1
View File
@@ -105,7 +105,6 @@ RUN addgroup -g 5000 vmail \
dovecot-submissiond \ dovecot-submissiond \
dovecot-pigeonhole-plugin \ dovecot-pigeonhole-plugin \
dovecot-pop3d \ dovecot-pop3d \
dovecot-fts-solr \
dovecot-fts-flatcurve \ dovecot-fts-flatcurve \
&& arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) \ && arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) \
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$arch" \ && wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$arch" \
+1 -1
View File
@@ -2,7 +2,7 @@
source /source_env.sh source /source_env.sh
MAX_AGE=$(redis-cli --raw -h redis-mailcow GET Q_MAX_AGE) MAX_AGE=$(redis-cli --raw -h redis-mailcow -a ${REDISPASS} --no-auth-warning GET Q_MAX_AGE)
if [[ -z ${MAX_AGE} ]]; then if [[ -z ${MAX_AGE} ]]; then
echo "Max age for quarantine items not defined" echo "Max age for quarantine items not defined"
+17 -58
View File
@@ -14,9 +14,9 @@ done
# Do not attempt to write to slave # Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}" REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
else else
REDIS_CMDLINE="redis-cli -h redis -p 6379" REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
fi fi
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
@@ -110,21 +110,16 @@ EOF
echo -n ${ACL_ANYONE} > /etc/dovecot/acl_anyone echo -n ${ACL_ANYONE} > /etc/dovecot/acl_anyone
if [[ "${FLATCURVE_EXPERIMENTAL}" =~ ^([yY][eE][sS]|[yY]) ]]; then if [[ "${SKIP_FTS}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo -e "\e[33mActivating Flatcurve as FTS Backend...\e[0m" echo -e "\e[33mDetecting SKIP_FTS=y... not enabling Flatcurve (FTS) then...\e[0m"
echo -e "\e[33mDepending on your previous setup a full reindex might be needed... \e[0m"
echo -e "\e[34mVisit https://docs.mailcow.email/manual-guides/Dovecot/u_e-dovecot-fts/#fts-related-dovecot-commands to learn how to reindex\e[0m"
echo -n 'quota acl zlib mail_crypt mail_crypt_acl mail_log notify fts fts_flatcurve listescape replication lazy_expunge' > /etc/dovecot/mail_plugins
echo -n 'quota imap_quota imap_acl acl zlib imap_zlib imap_sieve mail_crypt mail_crypt_acl notify mail_log fts fts_flatcurve listescape replication' > /etc/dovecot/mail_plugins_imap
echo -n 'quota sieve acl zlib mail_crypt mail_crypt_acl fts fts_flatcurve notify listescape replication' > /etc/dovecot/mail_plugins_lmtp
elif [[ "${SKIP_SOLR}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo -n 'quota acl zlib mail_crypt mail_crypt_acl mail_log notify listescape replication lazy_expunge' > /etc/dovecot/mail_plugins echo -n 'quota acl zlib mail_crypt mail_crypt_acl mail_log notify listescape replication lazy_expunge' > /etc/dovecot/mail_plugins
echo -n 'quota imap_quota imap_acl acl zlib imap_zlib imap_sieve mail_crypt mail_crypt_acl notify listescape replication mail_log' > /etc/dovecot/mail_plugins_imap echo -n 'quota imap_quota imap_acl acl zlib imap_zlib imap_sieve mail_crypt mail_crypt_acl notify listescape replication mail_log' > /etc/dovecot/mail_plugins_imap
echo -n 'quota sieve acl zlib mail_crypt mail_crypt_acl notify listescape replication' > /etc/dovecot/mail_plugins_lmtp echo -n 'quota sieve acl zlib mail_crypt mail_crypt_acl notify listescape replication' > /etc/dovecot/mail_plugins_lmtp
else else
echo -n 'quota acl zlib mail_crypt mail_crypt_acl mail_log notify fts fts_solr listescape replication lazy_expunge' > /etc/dovecot/mail_plugins echo -e "\e[32mDetecting SKIP_FTS=n... enabling Flatcurve (FTS)\e[0m"
echo -n 'quota imap_quota imap_acl acl zlib imap_zlib imap_sieve mail_crypt mail_crypt_acl notify mail_log fts fts_solr listescape replication' > /etc/dovecot/mail_plugins_imap echo -n 'quota acl zlib mail_crypt mail_crypt_acl mail_log notify fts fts_flatcurve listescape replication lazy_expunge' > /etc/dovecot/mail_plugins
echo -n 'quota sieve acl zlib mail_crypt mail_crypt_acl fts fts_solr notify listescape replication' > /etc/dovecot/mail_plugins_lmtp echo -n 'quota imap_quota imap_acl acl zlib imap_zlib imap_sieve mail_crypt mail_crypt_acl notify mail_log fts fts_flatcurve listescape replication' > /etc/dovecot/mail_plugins_imap
echo -n 'quota sieve acl zlib mail_crypt mail_crypt_acl fts fts_flatcurve notify listescape replication' > /etc/dovecot/mail_plugins_lmtp
fi fi
chmod 644 /etc/dovecot/mail_plugins /etc/dovecot/mail_plugins_imap /etc/dovecot/mail_plugins_lmtp /templates/quarantine.tpl chmod 644 /etc/dovecot/mail_plugins /etc/dovecot/mail_plugins_imap /etc/dovecot/mail_plugins_lmtp /templates/quarantine.tpl
@@ -247,51 +242,6 @@ function script_deinit()
end end
EOF EOF
# Temporarily set FTS depending on user choice inside mailcow.conf. Will be removed as soon as Solr is dropped
if [[ "${FLATCURVE_EXPERIMENTAL}" =~ ^([yY][eE][sS]|[yY])$ ]]; then
cat <<EOF > /etc/dovecot/conf.d/fts.conf
# Autogenerated by mailcow
plugin {
fts_autoindex = yes
fts_autoindex_exclude = \Junk
fts_autoindex_exclude2 = \Trash
fts = flatcurve
# Maximum term length can be set via the 'maxlen' argument (maxlen is
# specified in bytes, not number of UTF-8 characters)
fts_tokenizer_email_address = maxlen=100
fts_tokenizer_generic = algorithm=simple maxlen=30
# These are not flatcurve settings, but required for Dovecot FTS. See
# Dovecot FTS Configuration link above for further information.
fts_languages = en es de
fts_tokenizers = generic email-address
# OPTIONAL: Recommended default FTS core configuration
fts_filters = normalizer-icu snowball stopwords
fts_filters_en = lowercase snowball english-possessive stopwords
}
EOF
elif [[ ! "${SKIP_SOLR}" =~ ^([yY][eE][sS]|[yY])$ ]]; then
cat <<EOF > /etc/dovecot/conf.d/fts.conf
# Autogenerated by mailcow
plugin {
fts = solr
fts_autoindex = yes
fts_autoindex_exclude = \Junk
fts_autoindex_exclude2 = \Trash
fts_solr = url=http://solr:8983/solr/dovecot-fts/
fts_tokenizers = generic email-address
fts_tokenizer_generic = algorithm=simple
fts_filters = normalizer-icu snowball stopwords
fts_filters_en = lowercase snowball english-possessive stopwords
}
EOF
fi
# Replace patterns in app-passdb.lua # Replace patterns in app-passdb.lua
sed -i "s/__DBUSER__/${DBUSER}/g" /etc/dovecot/lua/passwd-verify.lua sed -i "s/__DBUSER__/${DBUSER}/g" /etc/dovecot/lua/passwd-verify.lua
sed -i "s/__DBPASS__/${DBPASS}/g" /etc/dovecot/lua/passwd-verify.lua sed -i "s/__DBPASS__/${DBPASS}/g" /etc/dovecot/lua/passwd-verify.lua
@@ -398,6 +348,15 @@ mail_replica = tcp:${MAILCOW_REPLICA_IP}:${DOVEADM_REPLICA_PORT}
EOF EOF
fi fi
# Setting variables for indexer-worker inside fts.conf automatically according to mailcow.conf settings
if [[ "${SKIP_FTS}" =~ ^([nN][oO]|[nN])+$ ]]; then
echo -e "\e[94mConfiguring FTS Settings...\e[0m"
echo -e "\e[94mSetting FTS Memory Limit (per process) to ${FTS_HEAP} MB\e[0m"
sed -i "s/vsz_limit\s*=\s*[0-9]*\s*MB*/vsz_limit=${FTS_HEAP} MB/" /etc/dovecot/conf.d/fts.conf
echo -e "\e[94mSetting FTS Process Limit to ${FTS_PROCS}\e[0m"
sed -i "s/process_limit\s*=\s*[0-9]*/process_limit=${FTS_PROCS}/" /etc/dovecot/conf.d/fts.conf
fi
# 401 is user dovecot # 401 is user dovecot
if [[ ! -s /mail_crypt/ecprivkey.pem || ! -s /mail_crypt/ecpubkey.pem ]]; then if [[ ! -s /mail_crypt/ecprivkey.pem || ! -s /mail_crypt/ecpubkey.pem ]]; then
openssl ecparam -name prime256v1 -genkey | openssl pkey -out /mail_crypt/ecprivkey.pem openssl ecparam -name prime256v1 -genkey | openssl pkey -out /mail_crypt/ecprivkey.pem
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
if [[ "${SKIP_SOLR}" =~ ^([yY][eE][sS]|[yY])+$ && ! "${FLATCURVE_EXPERIMENTAL}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then if [[ "${SKIP_FTS}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
exit 0 exit 0
else else
doveadm fts optimize -A doveadm fts optimize -A
@@ -31,7 +31,7 @@ try:
while True: while True:
try: try:
r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0) r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0, password=os.environ['REDISPASS'])
r.ping() r.ping()
except Exception as ex: except Exception as ex:
print('%s - trying again...' % (ex)) print('%s - trying again...' % (ex))
+1 -1
View File
@@ -23,7 +23,7 @@ else:
while True: while True:
try: try:
r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0) r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0, username='quota_notify', password='')
r.ping() r.ping()
except Exception as ex: except Exception as ex:
print('%s - trying again...' % (ex)) print('%s - trying again...' % (ex))
+2 -2
View File
@@ -4,9 +4,9 @@ source /source_env.sh
# Do not attempt to write to slave # Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}" REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
else else
REDIS_CMDLINE="redis-cli -h redis -p 6379" REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
fi fi
# Is replication active? # Is replication active?
+1 -1
View File
@@ -11,7 +11,7 @@ else
fi fi
# Deploy # Deploy
if curl --connect-timeout 15 --retry 10 --max-time 30 https://www.spamassassin.heinlein-support.de/$(dig txt 1.4.3.spamassassin.heinlein-support.de +short | tr -d '"' | tr -dc '0-9').tar.gz --output /tmp/sa-rules-heinlein.tar.gz; then if curl --connect-timeout 15 --retry 5 --max-time 30 https://www.spamassassin.heinlein-support.de/$(dig txt 1.4.3.spamassassin.heinlein-support.de +short | tr -d '"' | tr -dc '0-9').tar.gz --output /tmp/sa-rules-heinlein.tar.gz; then
if gzip -t /tmp/sa-rules-heinlein.tar.gz; then if gzip -t /tmp/sa-rules-heinlein.tar.gz; then
tar xfvz /tmp/sa-rules-heinlein.tar.gz -C /tmp/sa-rules-heinlein tar xfvz /tmp/sa-rules-heinlein.tar.gz -C /tmp/sa-rules-heinlein
cat /tmp/sa-rules-heinlein/*cf > /etc/rspamd/custom/sa-rules cat /tmp/sa-rules-heinlein/*cf > /etc/rspamd/custom/sa-rules
@@ -20,6 +20,7 @@ destination d_redis_ui_log {
host("`REDIS_SLAVEOF_IP`") host("`REDIS_SLAVEOF_IP`")
persist-name("redis1") persist-name("redis1")
port(`REDIS_SLAVEOF_PORT`) port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n") command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
); );
}; };
@@ -28,6 +29,7 @@ destination d_redis_f2b_channel {
host("`REDIS_SLAVEOF_IP`") host("`REDIS_SLAVEOF_IP`")
persist-name("redis2") persist-name("redis2")
port(`REDIS_SLAVEOF_PORT`) port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)") command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
); );
}; };
@@ -36,8 +38,13 @@ filter f_replica {
not match("User has no mail_replica in userdb" value("MESSAGE")); not match("User has no mail_replica in userdb" value("MESSAGE"));
not match("Error: sync: Unknown user in remote" value("MESSAGE")); not match("Error: sync: Unknown user in remote" value("MESSAGE"));
}; };
filter f_dovecot_auth_try {
not match("- trying the next passdb" value("MESSAGE")) and
not match("- trying the next userdb" value("MESSAGE"));
};
log { log {
source(s_dgram); source(s_dgram);
filter(f_dovecot_auth_try);
filter(f_replica); filter(f_replica);
destination(d_stdout); destination(d_stdout);
filter(f_mail); filter(f_mail);
+7
View File
@@ -20,6 +20,7 @@ destination d_redis_ui_log {
host("redis-mailcow") host("redis-mailcow")
persist-name("redis1") persist-name("redis1")
port(6379) port(6379)
auth("`REDISPASS`")
command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n") command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
); );
}; };
@@ -28,6 +29,7 @@ destination d_redis_f2b_channel {
host("redis-mailcow") host("redis-mailcow")
persist-name("redis2") persist-name("redis2")
port(6379) port(6379)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)") command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
); );
}; };
@@ -36,8 +38,13 @@ filter f_replica {
not match("User has no mail_replica in userdb" value("MESSAGE")); not match("User has no mail_replica in userdb" value("MESSAGE"));
not match("Error: sync: Unknown user in remote" value("MESSAGE")); not match("Error: sync: Unknown user in remote" value("MESSAGE"));
}; };
filter f_dovecot_auth_try {
not match("- trying the next passdb" value("MESSAGE")) and
not match("- trying the next userdb" value("MESSAGE"));
};
log { log {
source(s_dgram); source(s_dgram);
filter(f_dovecot_auth_try);
filter(f_replica); filter(f_replica);
destination(d_stdout); destination(d_stdout);
filter(f_mail); filter(f_mail);
+2 -2
View File
@@ -10,9 +10,9 @@ catch_non_zero() {
source /source_env.sh source /source_env.sh
# Do not attempt to write to slave # Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}" REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
else else
REDIS_CMDLINE="redis-cli -h redis -p 6379" REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
fi fi
catch_non_zero "${REDIS_CMDLINE} LTRIM ACME_LOG 0 ${LOG_LINES}" catch_non_zero "${REDIS_CMDLINE} LTRIM ACME_LOG 0 ${LOG_LINES}"
catch_non_zero "${REDIS_CMDLINE} LTRIM POSTFIX_MAILLOG 0 ${LOG_LINES}" catch_non_zero "${REDIS_CMDLINE} LTRIM POSTFIX_MAILLOG 0 ${LOG_LINES}"
+6 -7
View File
@@ -85,11 +85,10 @@ def refreshF2bregex():
f2bregex[3] = r'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed: (?!.*Connection lost to authentication server).+' f2bregex[3] = r'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed: (?!.*Connection lost to authentication server).+'
f2bregex[4] = r'warning: non-SMTP command from .*\[([0-9a-f\.:]+)]:.+' f2bregex[4] = r'warning: non-SMTP command from .*\[([0-9a-f\.:]+)]:.+'
f2bregex[5] = r'NOQUEUE: reject: RCPT from \[([0-9a-f\.:]+)].+Protocol error.+' f2bregex[5] = r'NOQUEUE: reject: RCPT from \[([0-9a-f\.:]+)].+Protocol error.+'
f2bregex[6] = r'-login: Disconnected.+ \(auth failed, .+\): user=.*, method=.+, rip=([0-9a-f\.:]+),' f2bregex[6] = r'\w+\([^,]+,([0-9a-f\.:]+),<[^>]+>\): Password mismatch \(SHA1 of given password: [a-f0-9]+\)'
f2bregex[7] = r'-login: Aborted login.+ \(auth failed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+' f2bregex[7] = r'\w+\([^,]+,([0-9a-f\.:]+),<[^>]+>\): unknown user \(SHA1 of given password: [a-f0-9]+\)'
f2bregex[8] = r'-login: Aborted login.+ \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+' f2bregex[8] = r'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
f2bregex[9] = r'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked' f2bregex[9] = r'([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
f2bregex[10] = r'([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
r.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False)) r.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False))
else: else:
try: try:
@@ -434,9 +433,9 @@ if __name__ == '__main__':
redis_slaveof_ip = os.getenv('REDIS_SLAVEOF_IP', '') redis_slaveof_ip = os.getenv('REDIS_SLAVEOF_IP', '')
redis_slaveof_port = os.getenv('REDIS_SLAVEOF_PORT', '') redis_slaveof_port = os.getenv('REDIS_SLAVEOF_PORT', '')
if "".__eq__(redis_slaveof_ip): if "".__eq__(redis_slaveof_ip):
r = redis.StrictRedis(host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0) r = redis.StrictRedis(host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0, password=os.environ['REDISPASS'])
else: else:
r = redis.StrictRedis(host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0) r = redis.StrictRedis(host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0, password=os.environ['REDISPASS'])
r.ping() r.ping()
pubsub = r.pubsub() pubsub = r.pubsub()
except Exception as ex: except Exception as ex:
+18
View File
@@ -0,0 +1,18 @@
FROM nginx:alpine
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
ENV PIP_BREAK_SYSTEM_PACKAGES=1
RUN apk add --no-cache nginx \
python3 \
py3-pip && \
pip install --upgrade pip && \
pip install Jinja2
RUN mkdir -p /etc/nginx/includes
COPY ./bootstrap.py /
COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]
+100
View File
@@ -0,0 +1,100 @@
import os
import subprocess
from jinja2 import Environment, FileSystemLoader
def includes_conf(env, template_vars):
server_name = "server_name.active"
listen_plain = "listen_plain.active"
listen_ssl = "listen_ssl.active"
server_name_config = f"server_name {template_vars['MAILCOW_HOSTNAME']} autodiscover.* autoconfig.* {' '.join(template_vars['ADDITIONAL_SERVER_NAMES'])};"
listen_plain_config = f"listen {template_vars['HTTP_PORT']};"
listen_ssl_config = f"listen {template_vars['HTTPS_PORT']};"
if not template_vars['DISABLE_IPv6']:
listen_plain_config += f"\nlisten [::]:{template_vars['HTTP_PORT']};"
listen_ssl_config += f"\nlisten [::]:{template_vars['HTTPS_PORT']} ssl;"
listen_ssl_config += "\nhttp2 on;"
with open(f"/etc/nginx/conf.d/{server_name}", "w") as f:
f.write(server_name_config)
with open(f"/etc/nginx/conf.d/{listen_plain}", "w") as f:
f.write(listen_plain_config)
with open(f"/etc/nginx/conf.d/{listen_ssl}", "w") as f:
f.write(listen_ssl_config)
def sites_default_conf(env, template_vars):
config_name = "sites-default.conf"
template = env.get_template(f"{config_name}.j2")
config = template.render(template_vars)
with open(f"/etc/nginx/includes/{config_name}", "w") as f:
f.write(config)
def nginx_conf(env, template_vars):
config_name = "nginx.conf"
template = env.get_template(f"{config_name}.j2")
config = template.render(template_vars)
with open(f"/etc/nginx/{config_name}", "w") as f:
f.write(config)
def prepare_template_vars():
ipv4_network = os.getenv("IPV4_NETWORK", "172.22.1")
additional_server_names = os.getenv("ADDITIONAL_SERVER_NAMES", "")
trusted_proxies = os.getenv("TRUSTED_PROXIES", "")
template_vars = {
'IPV4_NETWORK': ipv4_network,
'TRUSTED_PROXIES': [item.strip() for item in trusted_proxies.split(",") if item.strip()],
'SKIP_RSPAMD': os.getenv("SKIP_RSPAMD", "n").lower() in ("y", "yes"),
'SKIP_SOGO': os.getenv("SKIP_SOGO", "n").lower() in ("y", "yes"),
'NGINX_USE_PROXY_PROTOCOL': os.getenv("NGINX_USE_PROXY_PROTOCOL", "n").lower() in ("y", "yes"),
'MAILCOW_HOSTNAME': os.getenv("MAILCOW_HOSTNAME", ""),
'ADDITIONAL_SERVER_NAMES': [item.strip() for item in additional_server_names.split(",") if item.strip()],
'HTTP_PORT': os.getenv("HTTP_PORT", "80"),
'HTTPS_PORT': os.getenv("HTTPS_PORT", "443"),
'SOGOHOST': os.getenv("SOGOHOST", ipv4_network + ".248"),
'RSPAMDHOST': os.getenv("RSPAMDHOST", "rspamd-mailcow"),
'PHPFPMHOST': os.getenv("PHPFPMHOST", "php-fpm-mailcow"),
'DISABLE_IPv6': os.getenv("DISABLE_IPv6", "n").lower() in ("y", "yes"),
'HTTP_REDIRECT': os.getenv("HTTP_REDIRECT", "n").lower() in ("y", "yes"),
}
ssl_dir = '/etc/ssl/mail/'
template_vars['valid_cert_dirs'] = []
for d in os.listdir(ssl_dir):
full_path = os.path.join(ssl_dir, d)
if not os.path.isdir(full_path):
continue
cert_path = os.path.join(full_path, 'cert.pem')
key_path = os.path.join(full_path, 'key.pem')
domains_path = os.path.join(full_path, 'domains')
if os.path.isfile(cert_path) and os.path.isfile(key_path) and os.path.isfile(domains_path):
with open(domains_path, 'r') as file:
domains = file.read().strip()
domains_list = domains.split()
if domains_list and template_vars["MAILCOW_HOSTNAME"] not in domains_list:
template_vars['valid_cert_dirs'].append({
'cert_path': full_path + '/',
'domains': domains
})
return template_vars
def main():
env = Environment(loader=FileSystemLoader('./etc/nginx/conf.d/templates'))
# Render config
print("Render config")
template_vars = prepare_template_vars()
sites_default_conf(env, template_vars)
nginx_conf(env, template_vars)
includes_conf(env, template_vars)
if __name__ == "__main__":
main()
+26
View File
@@ -0,0 +1,26 @@
#!/bin/sh
PHPFPMHOST=${PHPFPMHOST:-"php-fpm-mailcow"}
SOGOHOST=${SOGOHOST:-"$IPV4_NETWORK.248"}
RSPAMDHOST=${RSPAMDHOST:-"rspamd-mailcow"}
until ping ${PHPFPMHOST} -c1 > /dev/null; do
echo "Waiting for PHP..."
sleep 1
done
if ! printf "%s\n" "${SKIP_SOGO}" | grep -E '^([yY][eE][sS]|[yY])+$' >/dev/null; then
until ping ${SOGOHOST} -c1 > /dev/null; do
echo "Waiting for SOGo..."
sleep 1
done
fi
if ! printf "%s\n" "${SKIP_RSPAMD}" | grep -E '^([yY][eE][sS]|[yY])+$' >/dev/null; then
until ping ${RSPAMDHOST} -c1 > /dev/null; do
echo "Waiting for Rspamd..."
sleep 1
done
fi
python3 /bootstrap.py
exec "$@"
+1 -1
View File
@@ -77,7 +77,7 @@ RUN apk add -U --no-cache autoconf \
--with-webp \ --with-webp \
--with-xpm \ --with-xpm \
--with-avif \ --with-avif \
&& docker-php-ext-install -j 4 exif gd gettext intl ldap opcache pcntl pdo pdo_mysql pspell soap sockets sysvsem zip bcmath gmp \ && docker-php-ext-install -j 4 exif gd gettext intl ldap opcache pcntl pdo pdo_mysql pspell soap sockets zip bcmath gmp \
&& docker-php-ext-configure imap --with-imap --with-imap-ssl \ && docker-php-ext-configure imap --with-imap --with-imap-ssl \
&& docker-php-ext-install -j 4 imap \ && docker-php-ext-install -j 4 imap \
&& curl --silent --show-error https://getcomposer.org/installer | php -- --version=${COMPOSER_VERSION} \ && curl --silent --show-error https://getcomposer.org/installer | php -- --version=${COMPOSER_VERSION} \
+2 -2
View File
@@ -16,7 +16,7 @@ else
REDIS_HOST="redis" REDIS_HOST="redis"
REDIS_PORT="6379" REDIS_PORT="6379"
fi fi
REDIS_CMDLINE="redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT}" REDIS_CMDLINE="redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} -a ${REDISPASS} --no-auth-warning"
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
echo "Waiting for Redis..." echo "Waiting for Redis..."
@@ -26,7 +26,7 @@ done
# Set redis session store # Set redis session store
echo -n ' echo -n '
session.save_handler = redis session.save_handler = redis
session.save_path = "tcp://'${REDIS_HOST}':'${REDIS_PORT}'" session.save_path = "tcp://'${REDIS_HOST}':'${REDIS_PORT}'?auth='${REDISPASS}'"
' > /usr/local/etc/php/conf.d/session_store.ini ' > /usr/local/etc/php/conf.d/session_store.ini
# Check mysql_upgrade (master and slave) # Check mysql_upgrade (master and slave)
+9 -1
View File
@@ -403,7 +403,6 @@ postscreen_dnsbl_sites = wl.mailspike.net=127.0.0.[18;19;20]*-2
list.dnswl.org=127.0.[0..255].1*-4 list.dnswl.org=127.0.[0..255].1*-4
list.dnswl.org=127.0.[0..255].2*-6 list.dnswl.org=127.0.[0..255].2*-6
list.dnswl.org=127.0.[0..255].3*-8 list.dnswl.org=127.0.[0..255].3*-8
ix.dnsbl.manitu.net*2
bl.spamcop.net*2 bl.spamcop.net*2
bl.suomispam.net*2 bl.suomispam.net*2
hostkarma.junkemailfilter.com=127.0.0.2*3 hostkarma.junkemailfilter.com=127.0.0.2*3
@@ -417,6 +416,10 @@ postscreen_dnsbl_sites = wl.mailspike.net=127.0.0.[18;19;20]*-2
bl.mailspike.net=127.0.0.[10;11;12]*4 bl.mailspike.net=127.0.0.[10;11;12]*4
EOF EOF
fi fi
# Remove discontinued DNSBLs from existing dns_blocklists.cf
sed -i '/ix\.dnsbl\.manitu\.net\*2/d' /opt/postfix/conf/dns_blocklists.cf # Nixspam
DNSBL_CONFIG=$(grep -v '^#' /opt/postfix/conf/dns_blocklists.cf | grep '\S') DNSBL_CONFIG=$(grep -v '^#' /opt/postfix/conf/dns_blocklists.cf | grep '\S')
if [ ! -z "$DNSBL_CONFIG" ]; then if [ ! -z "$DNSBL_CONFIG" ]; then
@@ -507,6 +510,11 @@ chgrp -R postdrop /var/spool/postfix/public
chgrp -R postdrop /var/spool/postfix/maildrop chgrp -R postdrop /var/spool/postfix/maildrop
postfix set-permissions postfix set-permissions
# Checking if there is a leftover of a crashed postfix container before starting a new one
if [ -e /var/spool/postfix/pid/master.pid ]; then
rm -rf /var/spool/postfix/pid/master.pid
fi
# Check Postfix configuration # Check Postfix configuration
postconf -c /opt/postfix/conf > /dev/null postconf -c /opt/postfix/conf > /dev/null
@@ -18,6 +18,7 @@ stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0 stderr_logfile_maxbytes=0
autorestart=true autorestart=true
startsecs=10
[eventlistener:processes] [eventlistener:processes]
command=/usr/local/sbin/stop-supervisor.sh command=/usr/local/sbin/stop-supervisor.sh
@@ -20,6 +20,7 @@ destination d_redis_ui_log {
host("`REDIS_SLAVEOF_IP`") host("`REDIS_SLAVEOF_IP`")
persist-name("redis1") persist-name("redis1")
port(`REDIS_SLAVEOF_PORT`) port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n") command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
); );
}; };
@@ -28,6 +29,7 @@ destination d_redis_f2b_channel {
host("`REDIS_SLAVEOF_IP`") host("`REDIS_SLAVEOF_IP`")
persist-name("redis2") persist-name("redis2")
port(`REDIS_SLAVEOF_PORT`) port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)") command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
); );
}; };
+2
View File
@@ -20,6 +20,7 @@ destination d_redis_ui_log {
host("redis-mailcow") host("redis-mailcow")
persist-name("redis1") persist-name("redis1")
port(6379) port(6379)
auth("`REDISPASS`")
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n") command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
); );
}; };
@@ -28,6 +29,7 @@ destination d_redis_f2b_channel {
host("redis-mailcow") host("redis-mailcow")
persist-name("redis2") persist-name("redis2")
port(6379) port(6379)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)") command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
); );
}; };
+1 -1
View File
@@ -2,7 +2,7 @@ FROM debian:bookworm-slim
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>" LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
ARG RSPAMD_VER=rspamd_3.10.2-1~b8a232043 ARG RSPAMD_VER=rspamd_3.11.0-2~90a175b45
ARG CODENAME=bookworm ARG CODENAME=bookworm
ENV LC_ALL=C ENV LC_ALL=C
+7 -5
View File
@@ -56,27 +56,29 @@ if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
cat <<EOF > /etc/rspamd/local.d/redis.conf cat <<EOF > /etc/rspamd/local.d/redis.conf
read_servers = "redis:6379"; read_servers = "redis:6379";
write_servers = "${REDIS_SLAVEOF_IP}:${REDIS_SLAVEOF_PORT}"; write_servers = "${REDIS_SLAVEOF_IP}:${REDIS_SLAVEOF_PORT}";
password = "${REDISPASS}";
timeout = 10; timeout = 10;
EOF EOF
until [[ $(redis-cli -h redis-mailcow PING) == "PONG" ]]; do until [[ $(redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning PING) == "PONG" ]]; do
echo "Waiting for Redis @redis-mailcow..." echo "Waiting for Redis @redis-mailcow..."
sleep 2 sleep 2
done done
until [[ $(redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} PING) == "PONG" ]]; do until [[ $(redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning PING) == "PONG" ]]; do
echo "Waiting for Redis @${REDIS_SLAVEOF_IP}..." echo "Waiting for Redis @${REDIS_SLAVEOF_IP}..."
sleep 2 sleep 2
done done
redis-cli -h redis-mailcow SLAVEOF ${REDIS_SLAVEOF_IP} ${REDIS_SLAVEOF_PORT} redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning SLAVEOF ${REDIS_SLAVEOF_IP} ${REDIS_SLAVEOF_PORT}
else else
cat <<EOF > /etc/rspamd/local.d/redis.conf cat <<EOF > /etc/rspamd/local.d/redis.conf
servers = "redis:6379"; servers = "redis:6379";
password = "${REDISPASS}";
timeout = 10; timeout = 10;
EOF EOF
until [[ $(redis-cli -h redis-mailcow PING) == "PONG" ]]; do until [[ $(redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning PING) == "PONG" ]]; do
echo "Waiting for Redis slave..." echo "Waiting for Redis slave..."
sleep 2 sleep 2
done done
redis-cli -h redis-mailcow SLAVEOF NO ONE redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning SLAVEOF NO ONE
fi fi
# Provide additional lua modules # Provide additional lua modules
+3 -4
View File
@@ -4,7 +4,7 @@ LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
ARG DEBIAN_VERSION=bookworm ARG DEBIAN_VERSION=bookworm
ARG SOGO_DEBIAN_REPOSITORY=http://www.axis.cz/linux/debian ARG SOGO_DEBIAN_REPOSITORY=https://packagingv2.sogo.nu/sogo-nightly-debian/
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?<version>.*)$ # renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?<version>.*)$
ARG GOSU_VERSION=1.17 ARG GOSU_VERSION=1.17
ENV LC_ALL=C ENV LC_ALL=C
@@ -33,9 +33,8 @@ RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \
&& gosu nobody true \ && gosu nobody true \
&& mkdir /usr/share/doc/sogo \ && mkdir /usr/share/doc/sogo \
&& touch /usr/share/doc/sogo/empty.sh \ && touch /usr/share/doc/sogo/empty.sh \
&& wget http://www.axis.cz/linux/debian/axis-archive-keyring.deb -O /tmp/axis-archive-keyring.deb \ && wget -O- https://keys.openpgp.org/vks/v1/by-fingerprint/74FFC6D72B925A34B5D356BDF8A27B36A6E2EAE9 | gpg --dearmor | apt-key add - \
&& apt install -y /tmp/axis-archive-keyring.deb \ && echo "deb [trusted=yes] ${SOGO_DEBIAN_REPOSITORY} ${DEBIAN_VERSION} main" > /etc/apt/sources.list.d/sogo.list \
&& echo "deb [trusted=yes] ${SOGO_DEBIAN_REPOSITORY} ${DEBIAN_VERSION} sogo-v5" > /etc/apt/sources.list.d/sogo.list \
&& apt-get update && apt-get install -y --no-install-recommends \ && apt-get update && apt-get install -y --no-install-recommends \
sogo \ sogo \
sogo-activesync \ sogo-activesync \
+2 -2
View File
@@ -240,8 +240,8 @@ chmod 600 /var/lib/sogo/GNUstep/Defaults/sogod.plist
# fi # fi
#fi #fi
# Copy logo, if any # Rename custom logo, if any
[[ -f /etc/sogo/sogo-full.svg ]] && cp /etc/sogo/sogo-full.svg /usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-full.svg [[ -f /etc/sogo/sogo-full.svg ]] && mv /etc/sogo/sogo-full.svg /etc/sogo/custom-fulllogo.svg
# Rsync web content # Rsync web content
echo "Syncing web content with named volume" echo "Syncing web content with named volume"
@@ -22,6 +22,7 @@ destination d_redis_ui_log {
host("`REDIS_SLAVEOF_IP`") host("`REDIS_SLAVEOF_IP`")
persist-name("redis1") persist-name("redis1")
port(`REDIS_SLAVEOF_PORT`) port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n") command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
); );
}; };
@@ -30,6 +31,7 @@ destination d_redis_f2b_channel {
host("`REDIS_SLAVEOF_IP`") host("`REDIS_SLAVEOF_IP`")
persist-name("redis2") persist-name("redis2")
port(`REDIS_SLAVEOF_PORT`) port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)") command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
); );
}; };
+2
View File
@@ -22,6 +22,7 @@ destination d_redis_ui_log {
host("redis-mailcow") host("redis-mailcow")
persist-name("redis1") persist-name("redis1")
port(6379) port(6379)
auth("`REDISPASS`")
command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n") command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
); );
}; };
@@ -30,6 +31,7 @@ destination d_redis_f2b_channel {
host("redis-mailcow") host("redis-mailcow")
persist-name("redis2") persist-name("redis2")
port(6379) port(6379)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)") command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
); );
}; };
-31
View File
@@ -1,31 +0,0 @@
FROM solr:7.7-slim
USER root
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=(?<version>.*)$
ARG GOSU_VERSION=1.17
COPY solr.sh /
COPY solr-config-7.7.0.xml /
COPY solr-schema-7.7.0.xml /
RUN dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" \
&& chmod +x /usr/local/bin/gosu \
&& gosu nobody true \
&& apt-get update && apt-get install -y --no-install-recommends \
tzdata \
curl \
bash \
zip \
&& apt-get autoclean \
&& rm -rf /var/lib/apt/lists/* \
&& chmod +x /solr.sh \
&& sync \
&& bash /solr.sh --bootstrap
RUN zip -q -d /opt/solr/server/lib/ext/log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
RUN apt remove zip -y
CMD ["/solr.sh"]
-289
View File
@@ -1,289 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!-- This is the default config with stuff non-essential to Dovecot removed. -->
<config>
<!-- Controls what version of Lucene various components of Solr
adhere to. Generally, you want to use the latest version to
get all bug fixes and improvements. It is highly recommended
that you fully re-index after changing this setting as it can
affect both how text is indexed and queried.
-->
<luceneMatchVersion>7.7.0</luceneMatchVersion>
<!-- A 'dir' option by itself adds any files found in the directory
to the classpath, this is useful for including all jars in a
directory.
When a 'regex' is specified in addition to a 'dir', only the
files in that directory which completely match the regex
(anchored on both ends) will be included.
If a 'dir' option (with or without a regex) is used and nothing
is found that matches, a warning will be logged.
The examples below can be used to load some solr-contribs along
with their external dependencies.
-->
<lib dir="${solr.install.dir:../../../..}/contrib/extraction/lib" regex=".*\.jar" />
<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-cell-\d.*\.jar" />
<lib dir="${solr.install.dir:../../../..}/contrib/clustering/lib/" regex=".*\.jar" />
<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-clustering-\d.*\.jar" />
<lib dir="${solr.install.dir:../../../..}/contrib/langid/lib/" regex=".*\.jar" />
<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-langid-\d.*\.jar" />
<lib dir="${solr.install.dir:../../../..}/contrib/velocity/lib" regex=".*\.jar" />
<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-velocity-\d.*\.jar" />
<!-- Data Directory
Used to specify an alternate directory to hold all index data
other than the default ./data under the Solr home. If
replication is in use, this should match the replication
configuration.
-->
<dataDir>${solr.data.dir:}</dataDir>
<!-- The default high-performance update handler -->
<updateHandler class="solr.DirectUpdateHandler2">
<!-- Enables a transaction log, used for real-time get, durability, and
and solr cloud replica recovery. The log can grow as big as
uncommitted changes to the index, so use of a hard autoCommit
is recommended (see below).
"dir" - the target directory for transaction logs, defaults to the
solr data directory.
"numVersionBuckets" - sets the number of buckets used to keep
track of max version values when checking for re-ordered
updates; increase this value to reduce the cost of
synchronizing access to version buckets during high-volume
indexing, this requires 8 bytes (long) * numVersionBuckets
of heap space per Solr core.
-->
<updateLog>
<str name="dir">${solr.ulog.dir:}</str>
<int name="numVersionBuckets">${solr.ulog.numVersionBuckets:65536}</int>
</updateLog>
<!-- AutoCommit
Perform a hard commit automatically under certain conditions.
Instead of enabling autoCommit, consider using "commitWithin"
when adding documents.
http://wiki.apache.org/solr/UpdateXmlMessages
maxDocs - Maximum number of documents to add since the last
commit before automatically triggering a new commit.
maxTime - Maximum amount of time in ms that is allowed to pass
since a document was added before automatically
triggering a new commit.
openSearcher - if false, the commit causes recent index changes
to be flushed to stable storage, but does not cause a new
searcher to be opened to make those changes visible.
If the updateLog is enabled, then it's highly recommended to
have some sort of hard autoCommit to limit the log size.
-->
<autoCommit>
<maxTime>${solr.autoCommit.maxTime:15000}</maxTime>
<openSearcher>false</openSearcher>
</autoCommit>
<!-- softAutoCommit is like autoCommit except it causes a
'soft' commit which only ensures that changes are visible
but does not ensure that data is synced to disk. This is
faster and more near-realtime friendly than a hard commit.
-->
<autoSoftCommit>
<maxTime>${solr.autoSoftCommit.maxTime:-1}</maxTime>
</autoSoftCommit>
<!-- Update Related Event Listeners
Various IndexWriter related events can trigger Listeners to
take actions.
postCommit - fired after every commit or optimize command
postOptimize - fired after every optimize command
-->
</updateHandler>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Query section - these settings control query time things like caches
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<query>
<!-- Solr Internal Query Caches
There are two implementations of cache available for Solr,
LRUCache, based on a synchronized LinkedHashMap, and
FastLRUCache, based on a ConcurrentHashMap.
FastLRUCache has faster gets and slower puts in single
threaded operation and thus is generally faster than LRUCache
when the hit ratio of the cache is high (> 75%), and may be
faster under other scenarios on multi-cpu systems.
-->
<!-- Filter Cache
Cache used by SolrIndexSearcher for filters (DocSets),
unordered sets of *all* documents that match a query. When a
new searcher is opened, its caches may be prepopulated or
"autowarmed" using data from caches in the old searcher.
autowarmCount is the number of items to prepopulate. For
LRUCache, the autowarmed items will be the most recently
accessed items.
Parameters:
class - the SolrCache implementation LRUCache or
(LRUCache or FastLRUCache)
size - the maximum number of entries in the cache
initialSize - the initial capacity (number of entries) of
the cache. (see java.util.HashMap)
autowarmCount - the number of entries to prepopulate from
and old cache.
maxRamMB - the maximum amount of RAM (in MB) that this cache is allowed
to occupy. Note that when this option is specified, the size
and initialSize parameters are ignored.
-->
<filterCache class="solr.FastLRUCache"
size="512"
initialSize="512"
autowarmCount="0"/>
<!-- Query Result Cache
Caches results of searches - ordered lists of document ids
(DocList) based on a query, a sort, and the range of documents requested.
Additional supported parameter by LRUCache:
maxRamMB - the maximum amount of RAM (in MB) that this cache is allowed
to occupy
-->
<queryResultCache class="solr.LRUCache"
size="512"
initialSize="512"
autowarmCount="0"/>
<!-- Document Cache
Caches Lucene Document objects (the stored fields for each
document). Since Lucene internal document ids are transient,
this cache will not be autowarmed.
-->
<documentCache class="solr.LRUCache"
size="512"
initialSize="512"
autowarmCount="0"/>
<!-- custom cache currently used by block join -->
<cache name="perSegFilter"
class="solr.search.LRUCache"
size="10"
initialSize="0"
autowarmCount="10"
regenerator="solr.NoOpRegenerator" />
<!-- Lazy Field Loading
If true, stored fields that are not requested will be loaded
lazily. This can result in a significant speed improvement
if the usual case is to not load all stored fields,
especially if the skipped fields are large compressed text
fields.
-->
<enableLazyFieldLoading>true</enableLazyFieldLoading>
<!-- Result Window Size
An optimization for use with the queryResultCache. When a search
is requested, a superset of the requested number of document ids
are collected. For example, if a search for a particular query
requests matching documents 10 through 19, and queryWindowSize is 50,
then documents 0 through 49 will be collected and cached. Any further
requests in that range can be satisfied via the cache.
-->
<queryResultWindowSize>20</queryResultWindowSize>
<!-- Maximum number of documents to cache for any entry in the
queryResultCache.
-->
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
<!-- Use Cold Searcher
If a search request comes in and there is no current
registered searcher, then immediately register the still
warming searcher and use it. If "false" then all requests
will block until the first searcher is done warming.
-->
<useColdSearcher>false</useColdSearcher>
</query>
<!-- Request Dispatcher
This section contains instructions for how the SolrDispatchFilter
should behave when processing requests for this SolrCore.
-->
<requestDispatcher>
<httpCaching never304="true" />
</requestDispatcher>
<!-- Request Handlers
http://wiki.apache.org/solr/SolrRequestHandler
Incoming queries will be dispatched to a specific handler by name
based on the path specified in the request.
If a Request Handler is declared with startup="lazy", then it will
not be initialized until the first request that uses it.
-->
<!-- SearchHandler
http://wiki.apache.org/solr/SearchHandler
For processing Search Queries, the primary Request Handler
provided with Solr is "SearchHandler" It delegates to a sequent
of SearchComponents (see below) and supports distributed
queries across multiple shards
-->
<requestHandler name="/select" class="solr.SearchHandler">
<!-- default values for query parameters can be specified, these
will be overridden by parameters in the request
-->
<lst name="defaults">
<str name="echoParams">explicit</str>
<int name="rows">10</int>
</lst>
</requestHandler>
<initParams path="/update/**,/select">
<lst name="defaults">
<str name="df">_text_</str>
</lst>
</initParams>
<!-- Response Writers
http://wiki.apache.org/solr/QueryResponseWriter
Request responses will be written using the writer specified by
the 'wt' request parameter matching the name of a registered
writer.
The "default" writer is the default and will be used if 'wt' is
not specified in the request.
-->
<queryResponseWriter name="xml"
default="true"
class="solr.XMLResponseWriter" />
</config>
@@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<schema name="dovecot-fts" version="2.0">
<fieldType name="string" class="solr.StrField" omitNorms="true" sortMissingLast="true"/>
<fieldType name="long" class="solr.LongPointField" positionIncrementGap="0"/>
<fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>
<fieldType name="text" class="solr.TextField" autoGeneratePhraseQueries="true" positionIncrementGap="100">
<analyzer type="index">
<tokenizer class="solr.StandardTokenizerFactory"/>
<filter class="solr.EdgeNGramFilterFactory" minGramSize="3" maxGramSize="20"/>
<filter class="solr.StopFilterFactory" words="stopwords.txt" ignoreCase="true"/>
<filter class="solr.WordDelimiterGraphFilterFactory" catenateNumbers="1" generateNumberParts="1" splitOnCaseChange="1" generateWordParts="1" splitOnNumerics="1" catenateAll="1" catenateWords="1"/>
<filter class="solr.FlattenGraphFilterFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/>
<filter class="solr.PorterStemFilterFactory"/>
</analyzer>
<analyzer type="query">
<tokenizer class="solr.StandardTokenizerFactory"/>
<filter class="solr.SynonymGraphFilterFactory" expand="true" ignoreCase="true" synonyms="synonyms.txt"/>
<filter class="solr.FlattenGraphFilterFactory"/>
<filter class="solr.StopFilterFactory" words="stopwords.txt" ignoreCase="true"/>
<filter class="solr.WordDelimiterGraphFilterFactory" catenateNumbers="1" generateNumberParts="1" splitOnCaseChange="1" generateWordParts="1" splitOnNumerics="1" catenateAll="1" catenateWords="1"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/>
<filter class="solr.PorterStemFilterFactory"/>
</analyzer>
</fieldType>
<field name="id" type="string" indexed="true" required="true" stored="true"/>
<field name="uid" type="long" indexed="true" required="true" stored="true"/>
<field name="box" type="string" indexed="true" required="true" stored="true"/>
<field name="user" type="string" indexed="true" required="true" stored="true"/>
<field name="hdr" type="text" indexed="true" stored="false"/>
<field name="body" type="text" indexed="true" stored="false"/>
<field name="from" type="text" indexed="true" stored="false"/>
<field name="to" type="text" indexed="true" stored="false"/>
<field name="cc" type="text" indexed="true" stored="false"/>
<field name="bcc" type="text" indexed="true" stored="false"/>
<field name="subject" type="text" indexed="true" stored="false"/>
<!-- Used by Solr internally: -->
<field name="_version_" type="long" indexed="true" stored="true"/>
<uniqueKey>id</uniqueKey>
</schema>
-75
View File
@@ -1,75 +0,0 @@
#!/bin/bash
if [[ "${FLATCURVE_EXPERIMENTAL}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo "FLATCURVE_EXPERIMENTAL=y, skipping Solr but enabling Flatcurve as FTS for Dovecot!"
echo "Solr will be removed in the future!"
sleep 365d
exit 0
elif [[ "${SKIP_SOLR}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo "SKIP_SOLR=y, skipping Solr..."
echo "HINT: You could try the newer FTS Backend Flatcurve, which is currently in experimental state..."
echo "Simply set FLATCURVE_EXPERIMENTAL=y inside your mailcow.conf and restart the stack afterwards!"
echo "Solr will be removed in the future!"
sleep 365d
exit 0
fi
MEM_TOTAL=$(awk '/MemTotal/ {print $2}' /proc/meminfo)
if [[ "${1}" != "--bootstrap" ]]; then
if [ ${MEM_TOTAL} -lt "2097152" ]; then
echo "System memory less than 2 GB, skipping Solr..."
sleep 365d
exit 0
fi
fi
set -e
# run the optional initdb
. /opt/docker-solr/scripts/run-initdb
# fixing volume permission
[[ -d /opt/solr/server/solr/dovecot-fts/data ]] && chown -R solr:solr /opt/solr/server/solr/dovecot-fts/data
if [[ "${1}" != "--bootstrap" ]]; then
sed -i '/SOLR_HEAP=/c\SOLR_HEAP="'${SOLR_HEAP:-1024}'m"' /opt/solr/bin/solr.in.sh
else
sed -i '/SOLR_HEAP=/c\SOLR_HEAP="256m"' /opt/solr/bin/solr.in.sh
fi
if [[ "${1}" == "--bootstrap" ]]; then
echo "Creating initial configuration"
echo "Modifying default config set"
cp /solr-config-7.7.0.xml /opt/solr/server/solr/configsets/_default/conf/solrconfig.xml
cp /solr-schema-7.7.0.xml /opt/solr/server/solr/configsets/_default/conf/schema.xml
rm /opt/solr/server/solr/configsets/_default/conf/managed-schema
echo "Starting local Solr instance to setup configuration"
gosu solr start-local-solr
echo "Creating core \"dovecot-fts\""
gosu solr /opt/solr/bin/solr create -c "dovecot-fts"
# See https://github.com/docker-solr/docker-solr/issues/27
echo "Checking core"
while ! wget -O - 'http://localhost:8983/solr/admin/cores?action=STATUS' | grep -q instanceDir; do
echo "Could not find any cores, waiting..."
sleep 3
done
echo "Created core \"dovecot-fts\""
echo "Stopping local Solr"
gosu solr stop-local-solr
exit 0
fi
echo "Starting up Solr..."
echo -e "\e[31mSolr is deprecated! You can try the new FTS System now by enabling FLATCURVE_EXPERIMENTAL=y inside mailcow.conf and restarting the stack\e[0m"
echo -e "\e[31mSolr will be removed completely soon!\e[0m"
sleep 15
exec gosu solr solr-foreground
+10 -10
View File
@@ -40,9 +40,9 @@ done
# Do not attempt to write to slave # Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}" REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
else else
REDIS_CMDLINE="redis-cli -h redis -p 6379" REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
fi fi
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
@@ -330,7 +330,7 @@ redis_checks() {
touch /tmp/redis-mailcow; echo "$(tail -50 /tmp/redis-mailcow)" > /tmp/redis-mailcow touch /tmp/redis-mailcow; echo "$(tail -50 /tmp/redis-mailcow)" > /tmp/redis-mailcow
host_ip=$(get_container_ip redis-mailcow) host_ip=$(get_container_ip redis-mailcow)
err_c_cur=${err_count} err_c_cur=${err_count}
/usr/lib/nagios/plugins/check_tcp -4 -H redis-mailcow -p 6379 -E -s "PING\n" -q "QUIT" -e "PONG" 2>> /tmp/redis-mailcow 1>&2; err_count=$(( ${err_count} + $? )) /usr/lib/nagios/plugins/check_tcp -4 -H redis-mailcow -p 6379 -E -s "AUTH ${REDISPASS}\nPING\n" -q "QUIT" -e "PONG" 2>> /tmp/redis-mailcow 1>&2; err_count=$(( ${err_count} + $? ))
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1 [ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} )) [ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
progress "Redis" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c} progress "Redis" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
@@ -503,12 +503,12 @@ dovecot_repl_checks() {
err_count=0 err_count=0
diff_c=0 diff_c=0
THRESHOLD=${DOVECOT_REPL_THRESHOLD} THRESHOLD=${DOVECOT_REPL_THRESHOLD}
D_REPL_STATUS=$(redis-cli -h redis -r GET DOVECOT_REPL_HEALTH) D_REPL_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning -r GET DOVECOT_REPL_HEALTH)
# Reduce error count by 2 after restarting an unhealthy container # Reduce error count by 2 after restarting an unhealthy container
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1 trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
while [ ${err_count} -lt ${THRESHOLD} ]; do while [ ${err_count} -lt ${THRESHOLD} ]; do
err_c_cur=${err_count} err_c_cur=${err_count}
D_REPL_STATUS=$(redis-cli --raw -h redis GET DOVECOT_REPL_HEALTH) D_REPL_STATUS=$(redis-cli --raw -h redis -a ${REDISPASS} --no-auth-warning GET DOVECOT_REPL_HEALTH)
if [[ "${D_REPL_STATUS}" != "1" ]]; then if [[ "${D_REPL_STATUS}" != "1" ]]; then
err_count=$(( ${err_count} + 1 )) err_count=$(( ${err_count} + 1 ))
fi fi
@@ -578,19 +578,19 @@ ratelimit_checks() {
err_count=0 err_count=0
diff_c=0 diff_c=0
THRESHOLD=${RATELIMIT_THRESHOLD} THRESHOLD=${RATELIMIT_THRESHOLD}
RL_LOG_STATUS=$(redis-cli -h redis LRANGE RL_LOG 0 0 | jq .qid) RL_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning LRANGE RL_LOG 0 0 | jq .qid)
# Reduce error count by 2 after restarting an unhealthy container # Reduce error count by 2 after restarting an unhealthy container
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1 trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
while [ ${err_count} -lt ${THRESHOLD} ]; do while [ ${err_count} -lt ${THRESHOLD} ]; do
err_c_cur=${err_count} err_c_cur=${err_count}
RL_LOG_STATUS_PREV=${RL_LOG_STATUS} RL_LOG_STATUS_PREV=${RL_LOG_STATUS}
RL_LOG_STATUS=$(redis-cli -h redis LRANGE RL_LOG 0 0 | jq .qid) RL_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning LRANGE RL_LOG 0 0 | jq .qid)
if [[ ${RL_LOG_STATUS_PREV} != ${RL_LOG_STATUS} ]]; then if [[ ${RL_LOG_STATUS_PREV} != ${RL_LOG_STATUS} ]]; then
err_count=$(( ${err_count} + 1 )) err_count=$(( ${err_count} + 1 ))
echo 'Last 10 applied ratelimits (may overlap with previous reports).' > /tmp/ratelimit echo 'Last 10 applied ratelimits (may overlap with previous reports).' > /tmp/ratelimit
echo 'Full ratelimit buckets can be emptied by deleting the ratelimit hash from within mailcow UI (see /debug -> Protocols -> Ratelimit):' >> /tmp/ratelimit echo 'Full ratelimit buckets can be emptied by deleting the ratelimit hash from within mailcow UI (see /debug -> Protocols -> Ratelimit):' >> /tmp/ratelimit
echo >> /tmp/ratelimit echo >> /tmp/ratelimit
redis-cli --raw -h redis LRANGE RL_LOG 0 10 | jq . >> /tmp/ratelimit redis-cli --raw -h redis -a ${REDISPASS} --no-auth-warning LRANGE RL_LOG 0 10 | jq . >> /tmp/ratelimit
fi fi
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1 [ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} )) [ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
@@ -673,7 +673,7 @@ acme_checks() {
err_count=0 err_count=0
diff_c=0 diff_c=0
THRESHOLD=${ACME_THRESHOLD} THRESHOLD=${ACME_THRESHOLD}
ACME_LOG_STATUS=$(redis-cli -h redis GET ACME_FAIL_TIME) ACME_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning GET ACME_FAIL_TIME)
if [[ -z "${ACME_LOG_STATUS}" ]]; then if [[ -z "${ACME_LOG_STATUS}" ]]; then
${REDIS_CMDLINE} SET ACME_FAIL_TIME 0 ${REDIS_CMDLINE} SET ACME_FAIL_TIME 0
ACME_LOG_STATUS=0 ACME_LOG_STATUS=0
@@ -685,7 +685,7 @@ acme_checks() {
ACME_LOG_STATUS_PREV=${ACME_LOG_STATUS} ACME_LOG_STATUS_PREV=${ACME_LOG_STATUS}
ACME_LC=0 ACME_LC=0
until [[ ! -z ${ACME_LOG_STATUS} ]] || [ ${ACME_LC} -ge 3 ]; do until [[ ! -z ${ACME_LOG_STATUS} ]] || [ ${ACME_LC} -ge 3 ]; do
ACME_LOG_STATUS=$(redis-cli -h redis GET ACME_FAIL_TIME 2> /dev/null) ACME_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning GET ACME_FAIL_TIME 2> /dev/null)
sleep 3 sleep 3
ACME_LC=$((ACME_LC+1)) ACME_LC=$((ACME_LC+1))
done done
-130
View File
@@ -1,130 +0,0 @@
map $http_x_forwarded_proto $client_req_scheme_nc {
default $scheme;
https https;
}
server {
include /etc/nginx/conf.d/listen_ssl.active;
include /etc/nginx/conf.d/listen_plain.active;
include /etc/nginx/mime.types;
charset utf-8;
override_charset on;
ssl_certificate /etc/ssl/mail/cert.pem;
ssl_certificate_key /etc/ssl/mail/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_ecdh_curve X25519:X448:secp384r1:secp256k1;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
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 "noindex, nofollow" always;
add_header X-XSS-Protection "1; mode=block" always;
fastcgi_hide_header X-Powered-By;
server_name NC_SUBD;
root /web/nextcloud/;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location = /.well-known/carddav {
return 301 $client_req_scheme_nc://$host/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $client_req_scheme_nc://$host/remote.php/dav;
}
location = /.well-known/webfinger {
return 301 $client_req_scheme_nc://$host/index.php/.well-known/webfinger;
}
location = /.well-known/nodeinfo {
return 301 $client_req_scheme_nc://$host/index.php/.well-known/nodeinfo;
}
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /web;
}
fastcgi_buffers 64 4K;
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 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;
set_real_ip_from fc00::/7;
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
location / {
rewrite ^ /index.php$uri;
}
location ~ ^\/(?:build|tests|config|lib|3rdparty|templates|data)\/ {
deny all;
}
location ~ ^\/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|ocs-provider\/.+)\.php(?:$|\/) {
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;
# Avoid sending the security headers twice
fastcgi_param modHeadersAvailable true;
# Enable pretty urls
fastcgi_param front_controller_active true;
fastcgi_pass phpfpm:9002;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
client_max_body_size 0;
fastcgi_read_timeout 1200;
}
location ~ ^\/(?:updater|ocs-provider)(?:$|\/) {
try_files $uri/ =404;
index index.php;
}
location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
try_files $uri /index.php$request_uri;
add_header Cache-Control "public, max-age=15778463";
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;
access_log off;
}
location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ {
try_files $uri /index.php$request_uri;
access_log off;
}
}
-2
View File
@@ -1,2 +0,0 @@
#!/bin/bash
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) php /web/nextcloud/occ ${@}
+6 -6
View File
@@ -1,8 +1,8 @@
-----BEGIN DH PARAMETERS----- -----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA9iHB0CRDhV8wfBgqnmvuJpl0fzL3qL75R4ZvQHlfMNLrxuIz2x9D MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
9zcDhPcBTVzV5Ay0AAkke4wP6r6wDQqXqBP4Y8IOkYAyLh3jM40jfHQzQt+5JdQl +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
ond3kiscBsFOch/vMfSLMu3lAb0YhPNTvrxhMz7LcVAWYl82swASupdiKR+MgaQr 87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
XsugpmDKsHW60VmIM9B7K9Y+rNHwvMWkmISd0KxA8oOy1WJvsVEissMALZDE3c4w YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
2xHmO2lXxgEx3aez28736t4m/KW3g9Zr31a1M0KusmfY//fGkPk4NUrLBOS2xrgp 7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
Y/rG1qSBdcVyerM0Ki93qCyHKYu4ene0OwIBAg== ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
-----END DH PARAMETERS----- -----END DH PARAMETERS-----
+37
View File
@@ -0,0 +1,37 @@
# mailcow FTS Flatcurve Settings, change them as you like.
plugin {
fts_autoindex = yes
fts_autoindex_exclude = \Junk
fts_autoindex_exclude2 = \Trash
# Tweak this setting if you only want to ensure big and frequent folders are indexed, not all.
fts_autoindex_max_recent_msgs = 20
fts = flatcurve
# Maximum term length can be set via the 'maxlen' argument (maxlen is
# specified in bytes, not number of UTF-8 characters)
fts_tokenizer_email_address = maxlen=100
fts_tokenizer_generic = algorithm=simple maxlen=30
# These are not flatcurve settings, but required for Dovecot FTS. See
# Dovecot FTS Configuration link above for further information.
fts_languages = en es de
fts_tokenizers = generic email-address
# OPTIONAL: Recommended default FTS core configuration
fts_filters = normalizer-icu snowball stopwords
fts_filters_en = lowercase snowball english-possessive stopwords
fts_index_timeout = 300s
}
### THIS PART WILL BE CHANGED BY MODIFYING mailcow.conf AUTOMATICALLY DURING RUNTIME! ###
service indexer-worker {
# Max amount of simultaniously running indexer jobs.
process_limit=1
# Max amount of RAM used by EACH indexer process.
vsz_limit=128 MB
}
### THIS PART WILL BE CHANGED BY MODIFYING mailcow.conf AUTOMATICALLY DURING RUNTIME! ###
+1
View File
@@ -278,6 +278,7 @@ imap_max_line_length = 2 M
#auth_cache_negative_ttl = 0 #auth_cache_negative_ttl = 0
#auth_cache_ttl = 30 s #auth_cache_ttl = 30 s
#auth_cache_size = 2 M #auth_cache_size = 2 M
auth_verbose_passwords = sha1:6
service replicator { service replicator {
process_min_avail = 1 process_min_avail = 1
} }
+2 -2
View File
@@ -1,7 +1,7 @@
[mysqld] [mysqld]
character-set-client-handshake = FALSE character-set-client-handshake = FALSE
character-set-server = utf8mb4 character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci collation-server = utf8mb4_general_ci
#innodb_file_per_table = TRUE #innodb_file_per_table = TRUE
#innodb_file_format = barracuda #innodb_file_format = barracuda
#innodb_large_prefix = TRUE #innodb_large_prefix = TRUE
@@ -20,7 +20,7 @@ thread_cache_size = 8
query_cache_type = 0 query_cache_type = 0
query_cache_size = 0 query_cache_size = 0
max_heap_table_size = 48M max_heap_table_size = 48M
thread_stack = 128K thread_stack = 256K
skip-host-cache skip-host-cache
skip-name-resolve skip-name-resolve
log-warnings = 0 log-warnings = 0
-3
View File
@@ -1,3 +0,0 @@
map_hash_max_size 256;
map_hash_bucket_size 256;
-19
View File
@@ -1,19 +0,0 @@
server {
listen 8081;
listen [::]:8081;
index index.php index.html;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /dynmaps;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9001;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
-242
View File
@@ -1,242 +0,0 @@
include /etc/nginx/mime.types;
charset utf-8;
override_charset on;
server_tokens off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_ecdh_curve X25519:X448:secp384r1:secp256k1;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
add_header Strict-Transport-Security "max-age=15768000;";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy strict-origin;
index index.php index.html;
client_max_body_size 0;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied off;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;
location ~ ^/(fonts|js|css|img)/ {
expires max;
add_header Cache-Control public;
}
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
fastcgi_hide_header X-Powered-By;
absolute_redirect off;
root /web;
location / {
try_files $uri $uri/ @strip-ext;
}
location /qhandler {
rewrite ^/qhandler/(.*)/(.*) /qhandler.php?action=$1&hash=$2;
}
location /edit {
rewrite ^/edit/(.*)/(.*) /edit.php?$1=$2;
}
location @strip-ext {
rewrite ^(.*)$ $1.php last;
}
location ~ ^/api/v1/(.*)$ {
try_files $uri $uri/ /json_api.php?query=$1&$args;
}
location ^~ /.well-known/acme-challenge/ {
allow all;
default_type "text/plain";
}
# If behind reverse proxy, forwards the correct IP
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
set_real_ip_from fc00::/7;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
rewrite ^/.well-known/caldav$ /SOGo/dav/ permanent;
rewrite ^/.well-known/carddav$ /SOGo/dav/ permanent;
location ^~ /principals {
return 301 /SOGo/dav;
}
location ^~ /inc/lib/ {
deny all;
return 403;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9002;
fastcgi_index index.php;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_read_timeout 3600;
fastcgi_send_timeout 3600;
}
location /rspamd/ {
location /rspamd/auth {
# proxy_pass is not inherited
proxy_pass http://rspamd:11334/auth;
proxy_intercept_errors on;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect off;
error_page 401 /_rspamderror.php;
}
proxy_pass http://rspamd:11334/;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect off;
}
location ~* ^/Autodiscover/Autodiscover.xml {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9002;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files /autodiscover.php =404;
}
location ~* ^/Autodiscover/Autodiscover.json {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9002;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files /autodiscover-json.php =404;
}
location ~ /(?:m|M)ail/(?:c|C)onfig-v1.1.xml {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9002;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files /autoconfig.php =404;
}
location /sogo-auth-verify {
internal;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header Content-Length "";
proxy_pass http://127.0.0.1:65510/sogo-auth;
proxy_pass_request_body off;
}
location ^~ /Microsoft-Server-ActiveSync {
include /etc/nginx/conf.d/includes/sogo_proxy_auth.conf;
include /etc/nginx/conf.d/sogo_eas.active;
proxy_connect_timeout 75;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
proxy_buffer_size 128k;
proxy_buffers 64 512k;
proxy_busy_buffers_size 512k;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
client_body_buffer_size 512k;
client_max_body_size 0;
}
location ^~ /SOGo {
location ~* ^/SOGo/so/.*\.(xml|js|html|xhtml)$ {
include /etc/nginx/conf.d/includes/sogo_proxy_auth.conf;
include /etc/nginx/conf.d/sogo.active;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header x-webobjects-server-protocol HTTP/1.0;
proxy_set_header x-webobjects-remote-host $remote_addr;
proxy_set_header x-webobjects-server-name $server_name;
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
proxy_set_header x-webobjects-server-port $server_port;
proxy_hide_header Content-Type;
add_header Content-Type text/plain;
break;
}
include /etc/nginx/conf.d/includes/sogo_proxy_auth.conf;
include /etc/nginx/conf.d/sogo.active;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header x-webobjects-server-protocol HTTP/1.0;
proxy_set_header x-webobjects-remote-host $remote_addr;
proxy_set_header x-webobjects-server-name $server_name;
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
proxy_set_header x-webobjects-server-port $server_port;
proxy_buffer_size 128k;
proxy_buffers 64 512k;
proxy_busy_buffers_size 512k;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
client_body_buffer_size 128k;
client_max_body_size 0;
break;
}
location ~* /sogo$ {
return 301 $client_req_scheme://$http_host/SOGo;
}
location /SOGo.woa/WebServerResources/ {
alias /usr/lib/GNUstep/SOGo/WebServerResources/;
}
location /.woa/WebServerResources/ {
alias /usr/lib/GNUstep/SOGo/WebServerResources/;
}
location /SOGo/WebServerResources/ {
alias /usr/lib/GNUstep/SOGo/WebServerResources/;
}
location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$) {
alias /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2;
}
include /etc/nginx/conf.d/site.*.custom;
error_page 502 @awaitingupstream;
location @awaitingupstream {
rewrite ^(.*)$ /_status.502.html break;
}
location ~ ^/cache/(.*)$ {
try_files $uri $uri/ /resource.php?file=$1;
}
@@ -1,8 +0,0 @@
auth_request /sogo-auth-verify;
auth_request_set $user $upstream_http_x_user;
auth_request_set $auth $upstream_http_x_auth;
auth_request_set $auth_type $upstream_http_x_auth_type;
proxy_set_header x-webobjects-remote-user "$user";
proxy_set_header Authorization "$auth";
proxy_set_header x-webobjects-auth-type "$auth_type";
-19
View File
@@ -1,19 +0,0 @@
server {
listen 9081;
index index.php index.html;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /meta_exporter;
client_max_body_size 10M;
location ~ \.php$ {
client_max_body_size 10M;
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass phpfpm:9001;
fastcgi_index pipe.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
-10
View File
@@ -1,10 +0,0 @@
proxy_cache_path /tmp levels=1:2 keys_zone=sogo:10m inactive=24h max_size=1g;
server_names_hash_max_size 512;
server_names_hash_bucket_size 128;
map $http_x_forwarded_proto $client_req_scheme {
default $scheme;
https https;
}
include /etc/nginx/conf.d/sites.active;
@@ -1,2 +0,0 @@
listen ${HTTP_PORT};
listen [::]:${HTTP_PORT};
@@ -1,3 +0,0 @@
listen ${HTTPS_PORT} ssl;
listen [::]:${HTTPS_PORT} ssl;
http2 on;
+188
View File
@@ -0,0 +1,188 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
# map-size.conf:
map_hash_max_size 256;
map_hash_bucket_size 256;
# site.conf:
proxy_cache_path /tmp levels=1:2 keys_zone=sogo:10m inactive=24h max_size=1g;
server_names_hash_max_size 512;
server_names_hash_bucket_size 128;
map $http_x_forwarded_proto $client_req_scheme {
default $scheme;
https https;
}
{% if HTTP_REDIRECT %}
# HTTP to HTTPS redirect
server {
root /web;
listen {{ HTTP_PORT }} default_server;
listen [::]:{{ HTTP_PORT }} default_server;
server_name {{ MAILCOW_HOSTNAME }} autodiscover.* autoconfig.* {{ ADDITIONAL_SERVER_NAMES | join(' ') }};
if ( $request_uri ~* "%0A|%0D" ) { return 403; }
location ^~ /.well-known/acme-challenge/ {
allow all;
default_type "text/plain";
}
location / {
return 301 https://$host$uri$is_args$args;
}
}
{%endif%}
# Default Server Name
server {
listen 127.0.0.1:65510; # sogo-auth verify internal
{% if not HTTP_REDIRECT %}
listen {{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
{%endif%}
listen {{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
{% if not DISABLE_IPv6 %}
{% if not HTTP_REDIRECT %}
listen [::]:{{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
{%endif%}
listen [::]:{{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
{%endif%}
http2 on;
ssl_certificate /etc/ssl/mail/cert.pem;
ssl_certificate_key /etc/ssl/mail/key.pem;
server_name {{ MAILCOW_HOSTNAME }} autodiscover.* autoconfig.*;
include /etc/nginx/includes/sites-default.conf;
}
# Additional Server Names
{% for SERVER_NAME in ADDITIONAL_SERVER_NAMES %}
server {
listen 127.0.0.1:65510; # sogo-auth verify internal
{% if not HTTP_REDIRECT %}
listen {{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
{%endif%}
listen {{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
{% if not DISABLE_IPv6 %}
{% if not HTTP_REDIRECT %}
listen [::]:{{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
{%endif%}
listen [::]:{{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
{%endif%}
http2 on;
ssl_certificate /etc/ssl/mail/cert.pem;
ssl_certificate_key /etc/ssl/mail/key.pem;
server_name {{ SERVER_NAME }};
include /etc/nginx/includes/sites-default.conf;
}
{% endfor %}
# rspamd dynmaps:
server {
listen 8081;
{% if not DISABLE_IPv6 %}
listen [::]:8081;
{%endif%}
index index.php index.html;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /dynmaps;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {{ PHPFPMHOST }}:9001;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
# rspamd meta_exporter:
server {
listen 9081;
index index.php index.html;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /meta_exporter;
client_max_body_size 10M;
location ~ \.php$ {
client_max_body_size 10M;
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {{ PHPFPMHOST }}:9001;
fastcgi_index pipe.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
{% for cert in valid_cert_dirs %}
server {
{% if not HTTP_REDIRECT %}
listen {{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
{%endif%}
listen {{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
{% if not DISABLE_IPv6 %}
{% if not HTTP_REDIRECT %}
listen [::]:{{ HTTP_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%};
{%endif%}
listen [::]:{{ HTTPS_PORT }}{% if NGINX_USE_PROXY_PROTOCOL %} proxy_protocol{%endif%} ssl;
{%endif%}
http2 on;
ssl_certificate {{ cert.cert_path }}cert.pem;
ssl_certificate_key {{ cert.cert_path }}key.pem;
server_name {{ cert.domains }};
include /etc/nginx/includes/sites-default.conf;
}
{% endfor %}
include /etc/nginx/conf.d/*.conf;
}
@@ -1 +0,0 @@
echo "server_name ${MAILCOW_HOSTNAME} autodiscover.* autoconfig.* $(echo ${ADDITIONAL_SERVER_NAMES} | tr ',' ' ');"
@@ -0,0 +1,287 @@
include /etc/nginx/mime.types;
charset utf-8;
override_charset on;
server_tokens off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_ecdh_curve X25519:X448:secp384r1:secp256k1;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
add_header Strict-Transport-Security "max-age=15768000;";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy strict-origin;
index index.php index.html;
client_max_body_size 0;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied off;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;
location ~ ^/(fonts|js|css|img)/ {
expires max;
add_header Cache-Control public;
}
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
fastcgi_hide_header X-Powered-By;
absolute_redirect off;
root /web;
# If behind reverse proxy, forwards the correct IP
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
set_real_ip_from fc00::/7;
{% for TRUSTED_PROXY in TRUSTED_PROXIES %}
set_real_ip_from {{ TRUSTED_PROXY }};
{% endfor %}
{% if not NGINX_USE_PROXY_PROTOCOL %}
real_ip_header X-Forwarded-For;
{% else %}
real_ip_header proxy_protocol;
{% endif %}
real_ip_recursive on;
location @strip-ext {
rewrite ^(.*)$ $1.php last;
}
location ^~ /inc/lib/ {
deny all;
return 403;
}
location ^~ /.well-known/acme-challenge/ {
allow all;
default_type "text/plain";
}
rewrite ^/.well-known/caldav$ /SOGo/dav/ permanent;
rewrite ^/.well-known/carddav$ /SOGo/dav/ permanent;
location / {
try_files $uri $uri/ @strip-ext;
}
location /qhandler {
rewrite ^/qhandler/(.*)/(.*) /qhandler.php?action=$1&hash=$2;
}
location /edit {
rewrite ^/edit/(.*)/(.*) /edit.php?$1=$2;
}
location ~ ^/api/v1/(.*)$ {
try_files $uri $uri/ /json_api.php?query=$1&$args;
}
location ~ ^/cache/(.*)$ {
try_files $uri $uri/ /resource.php?file=$1;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {{ PHPFPMHOST }}:9002;
fastcgi_index index.php;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_read_timeout 3600;
fastcgi_send_timeout 3600;
}
location ~* ^/Autodiscover/Autodiscover.xml {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {{ PHPFPMHOST }}:9002;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files /autodiscover.php =404;
}
location ~* ^/Autodiscover/Autodiscover.json {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {{ PHPFPMHOST }}:9002;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files /autodiscover-json.php =404;
}
location ~ /(?:m|M)ail/(?:c|C)onfig-v1.1.xml {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {{ PHPFPMHOST }}:9002;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files /autoconfig.php =404;
}
{% if not SKIP_RSPAMD %}
location /rspamd/ {
location /rspamd/auth {
# proxy_pass is not inherited
proxy_pass http://{{ RSPAMDHOST }}:11334/auth;
proxy_intercept_errors on;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%};
proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL %}$remote_addr{% else %}$proxy_protocol_addr{%endif%};
proxy_redirect off;
error_page 401 /_rspamderror.php;
}
proxy_pass http://{{ RSPAMDHOST }}:11334/;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%};
proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL %}$remote_addr{% else %}$proxy_protocol_addr{%endif%};
proxy_redirect off;
}
{% endif %}
{% if not SKIP_SOGO %}
location ^~ /principals {
return 301 /SOGo/dav;
}
location /sogo-auth-verify {
internal;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header Content-Length "";
proxy_pass http://127.0.0.1:65510/sogo-auth;
proxy_pass_request_body off;
}
location ^~ /Microsoft-Server-ActiveSync {
auth_request /sogo-auth-verify;
auth_request_set $user $upstream_http_x_user;
auth_request_set $auth $upstream_http_x_auth;
auth_request_set $auth_type $upstream_http_x_auth_type;
proxy_set_header x-webobjects-remote-user "$user";
proxy_set_header Authorization "$auth";
proxy_set_header x-webobjects-auth-type "$auth_type";
proxy_pass http://{{ SOGOHOST }}:20000/SOGo/Microsoft-Server-ActiveSync;
proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%};
proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL %}$remote_addr{% else %}$proxy_protocol_addr{%endif%};
proxy_connect_timeout 75;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
proxy_buffer_size 128k;
proxy_buffers 64 512k;
proxy_busy_buffers_size 512k;
proxy_set_header Host $http_host;
client_body_buffer_size 512k;
client_max_body_size 0;
}
location ^~ /SOGo {
location ~* ^/SOGo/so/.*\.(xml|js|html|xhtml)$ {
auth_request /sogo-auth-verify;
auth_request_set $user $upstream_http_x_user;
auth_request_set $auth $upstream_http_x_auth;
auth_request_set $auth_type $upstream_http_x_auth_type;
proxy_set_header x-webobjects-remote-user "$user";
proxy_set_header Authorization "$auth";
proxy_set_header x-webobjects-auth-type "$auth_type";
proxy_pass http://{{ SOGOHOST }}:20000;
proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%};
proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL %}$remote_addr{% else %}$proxy_protocol_addr{%endif%};
proxy_set_header Host $http_host;
proxy_set_header x-webobjects-server-protocol HTTP/1.0;
proxy_set_header x-webobjects-remote-host $remote_addr;
proxy_set_header x-webobjects-server-name $server_name;
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
proxy_set_header x-webobjects-server-port $server_port;
proxy_hide_header Content-Type;
add_header Content-Type text/plain;
break;
}
auth_request /sogo-auth-verify;
auth_request_set $user $upstream_http_x_user;
auth_request_set $auth $upstream_http_x_auth;
auth_request_set $auth_type $upstream_http_x_auth_type;
proxy_set_header x-webobjects-remote-user "$user";
proxy_set_header Authorization "$auth";
proxy_set_header x-webobjects-auth-type "$auth_type";
proxy_pass http://{{ SOGOHOST }}:20000;
proxy_set_header X-Forwarded-For {% if not NGINX_USE_PROXY_PROTOCOL %}$proxy_add_x_forwarded_for{% else %}$proxy_protocol_addr{%endif%};
proxy_set_header X-Real-IP {% if not NGINX_USE_PROXY_PROTOCOL %}$remote_addr{% else %}$proxy_protocol_addr{%endif%};
proxy_set_header Host $http_host;
proxy_set_header x-webobjects-server-protocol HTTP/1.0;
proxy_set_header x-webobjects-remote-host $remote_addr;
proxy_set_header x-webobjects-server-name $server_name;
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
proxy_set_header x-webobjects-server-port $server_port;
proxy_buffer_size 128k;
proxy_buffers 64 512k;
proxy_busy_buffers_size 512k;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
client_body_buffer_size 128k;
client_max_body_size 0;
break;
}
location ~* /sogo$ {
return 301 $client_req_scheme://$http_host/SOGo;
}
location /SOGo.woa/WebServerResources/ {
alias /usr/lib/GNUstep/SOGo/WebServerResources/;
}
location /.woa/WebServerResources/ {
alias /usr/lib/GNUstep/SOGo/WebServerResources/;
}
location /SOGo/WebServerResources/ {
alias /usr/lib/GNUstep/SOGo/WebServerResources/;
}
location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$) {
alias /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2;
}
{% endif %}
include /etc/nginx/conf.d/site.*.custom;
error_page 502 @awaitingupstream;
location @awaitingupstream {
rewrite ^(.*)$ /_status.502.html break;
}
location ~* \.php$ {
return 404;
}
location ~* \.twig$ {
return 404;
}
@@ -1,38 +0,0 @@
echo '
server {
listen 127.0.0.1:65510;
include /etc/nginx/conf.d/listen_plain.active;
include /etc/nginx/conf.d/listen_ssl.active;
ssl_certificate /etc/ssl/mail/cert.pem;
ssl_certificate_key /etc/ssl/mail/key.pem;
include /etc/nginx/conf.d/server_name.active;
include /etc/nginx/conf.d/includes/site-defaults.conf;
}
';
for cert_dir in /etc/ssl/mail/*/ ; do
if [[ ! -f ${cert_dir}domains ]] || [[ ! -f ${cert_dir}cert.pem ]] || [[ ! -f ${cert_dir}key.pem ]]; then
continue
fi
# do not create vhost for default-certificate. the cert is already in the default server listen
domains="$(cat ${cert_dir}domains | sed -e 's/^[[:space:]]*//')"
case "${domains}" in
"") continue;;
"${MAILCOW_HOSTNAME}"*) continue;;
esac
echo -n '
server {
include /etc/nginx/conf.d/listen_ssl.active;
ssl_certificate '${cert_dir}'cert.pem;
ssl_certificate_key '${cert_dir}'key.pem;
';
echo -n '
server_name '${domains}';
include /etc/nginx/conf.d/includes/site-defaults.conf;
}
';
done
-1
View File
@@ -1 +0,0 @@
proxy_pass http://${IPV4_NETWORK}.248:20000;
@@ -1,5 +0,0 @@
if printf "%s\n" "${SKIP_SOGO}" | grep -E '^([yY][eE][sS]|[yY])+$' >/dev/null; then
echo "return 410;"
else
echo "proxy_pass http://${IPV4_NETWORK}.248:20000/SOGo/Microsoft-Server-ActiveSync;"
fi
+2 -3
View File
@@ -162,10 +162,9 @@ transport_maps = pcre:/opt/postfix/conf/custom_transport.pcre,
proxy:mysql:/opt/postfix/conf/sql/mysql_relay_ne.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_relay_ne.cf,
proxy:mysql:/opt/postfix/conf/sql/mysql_transport_maps.cf proxy:mysql:/opt/postfix/conf/sql/mysql_transport_maps.cf
smtp_sasl_auth_soft_bounce = no smtp_sasl_auth_soft_bounce = no
postscreen_discard_ehlo_keywords = silent-discard, dsn, chunking postscreen_discard_ehlo_keywords = chunking, silent-discard, smtputf8, dsn
smtpd_discard_ehlo_keywords = chunking, silent-discard smtpd_discard_ehlo_keywords = chunking, silent-discard, smtputf8
compatibility_level = 3.7 compatibility_level = 3.7
smtputf8_enable = no
# Define protocols for SMTPS and submission service # Define protocols for SMTPS and submission service
submission_smtpd_tls_mandatory_protocols = >=TLSv1.2 submission_smtpd_tls_mandatory_protocols = >=TLSv1.2
smtps_smtpd_tls_mandatory_protocols = >=TLSv1.2 smtps_smtpd_tls_mandatory_protocols = >=TLSv1.2
+30 -59
View File
@@ -1,6 +1,6 @@
# Whitelist generated by Postwhite v3.4 on Fri Nov 1 00:18:49 UTC 2024 # Whitelist generated by Postwhite v3.4 on Sat Feb 1 00:18:03 UTC 2025
# https://github.com/stevejenkins/postwhite/ # https://github.com/stevejenkins/postwhite/
# 2013 total rules # 1984 total rules
2a00:1450:4000::/36 permit 2a00:1450:4000::/36 permit
2a01:111:f400::/48 permit 2a01:111:f400::/48 permit
2a01:111:f403:8000::/50 permit 2a01:111:f403:8000::/50 permit
@@ -19,8 +19,7 @@
8.20.114.31 permit 8.20.114.31 permit
8.25.194.0/23 permit 8.25.194.0/23 permit
8.25.196.0/23 permit 8.25.196.0/23 permit
8.39.54.0/23 permit 10.162.0.0/16 permit
8.40.222.0/23 permit
12.130.86.238 permit 12.130.86.238 permit
13.110.208.0/21 permit 13.110.208.0/21 permit
13.110.209.0/24 permit 13.110.209.0/24 permit
@@ -31,9 +30,11 @@
15.200.21.50 permit 15.200.21.50 permit
15.200.44.248 permit 15.200.44.248 permit
15.200.201.185 permit 15.200.201.185 permit
17.41.0.0/16 permit
17.57.155.0/24 permit 17.57.155.0/24 permit
17.57.156.0/24 permit 17.57.156.0/24 permit
17.58.0.0/16 permit 17.58.0.0/16 permit
17.142.0.0/15 permit
17.143.234.140/30 permit 17.143.234.140/30 permit
18.156.89.250 permit 18.156.89.250 permit
18.157.243.190 permit 18.157.243.190 permit
@@ -93,6 +94,7 @@
27.123.206.76/30 permit 27.123.206.76/30 permit
27.123.206.80/28 permit 27.123.206.80/28 permit
31.25.48.222 permit 31.25.48.222 permit
31.47.251.17 permit
34.195.217.107 permit 34.195.217.107 permit
34.212.163.75 permit 34.212.163.75 permit
34.215.104.144 permit 34.215.104.144 permit
@@ -105,6 +107,7 @@
35.191.0.0/16 permit 35.191.0.0/16 permit
35.205.92.9 permit 35.205.92.9 permit
35.242.169.159 permit 35.242.169.159 permit
37.188.97.188 permit
37.218.248.47 permit 37.218.248.47 permit
37.218.249.47 permit 37.218.249.47 permit
37.218.251.62 permit 37.218.251.62 permit
@@ -116,7 +119,6 @@
40.233.64.216 permit 40.233.64.216 permit
40.233.83.78 permit 40.233.83.78 permit
40.233.88.28 permit 40.233.88.28 permit
43.228.184.0/22 permit
44.206.138.57 permit 44.206.138.57 permit
44.217.45.156 permit 44.217.45.156 permit
44.236.56.93 permit 44.236.56.93 permit
@@ -325,7 +327,6 @@
65.110.161.77 permit 65.110.161.77 permit
65.123.29.213 permit 65.123.29.213 permit
65.123.29.220 permit 65.123.29.220 permit
65.154.166.0/24 permit
65.212.180.36 permit 65.212.180.36 permit
66.102.0.0/20 permit 66.102.0.0/20 permit
66.119.150.192/26 permit 66.119.150.192/26 permit
@@ -445,6 +446,7 @@
69.171.244.0/23 permit 69.171.244.0/23 permit
70.37.151.128/25 permit 70.37.151.128/25 permit
70.42.149.35 permit 70.42.149.35 permit
72.3.185.0/24 permit
72.14.192.0/18 permit 72.14.192.0/18 permit
72.21.192.0/19 permit 72.21.192.0/19 permit
72.21.217.142 permit 72.21.217.142 permit
@@ -505,6 +507,9 @@
72.30.239.228/31 permit 72.30.239.228/31 permit
72.30.239.244/30 permit 72.30.239.244/30 permit
72.30.239.248/31 permit 72.30.239.248/31 permit
72.32.154.0/24 permit
72.32.217.0/24 permit
72.32.243.0/24 permit
72.52.72.32/28 permit 72.52.72.32/28 permit
74.6.128.0/24 permit 74.6.128.0/24 permit
74.6.129.0/24 permit 74.6.129.0/24 permit
@@ -620,6 +625,7 @@
89.22.108.0/24 permit 89.22.108.0/24 permit
91.211.240.0/22 permit 91.211.240.0/22 permit
94.169.2.0/23 permit 94.169.2.0/23 permit
94.236.119.0/26 permit
94.245.112.0/27 permit 94.245.112.0/27 permit
94.245.112.10/31 permit 94.245.112.10/31 permit
95.131.104.0/21 permit 95.131.104.0/21 permit
@@ -1114,12 +1120,11 @@
98.139.245.212/31 permit 98.139.245.212/31 permit
99.78.197.208/28 permit 99.78.197.208/28 permit
99.83.190.102 permit 99.83.190.102 permit
103.2.140.0/22 permit
103.9.96.0/22 permit 103.9.96.0/22 permit
103.28.42.0/24 permit 103.28.42.0/24 permit
103.47.204.0/22 permit
103.151.192.0/23 permit 103.151.192.0/23 permit
103.168.172.128/27 permit 103.168.172.128/27 permit
103.237.104.0/22 permit
104.43.243.237 permit 104.43.243.237 permit
104.44.112.128/25 permit 104.44.112.128/25 permit
104.47.0.0/17 permit 104.47.0.0/17 permit
@@ -1285,9 +1290,6 @@
117.120.16.0/21 permit 117.120.16.0/21 permit
119.42.242.52/31 permit 119.42.242.52/31 permit
119.42.242.156 permit 119.42.242.156 permit
121.244.91.48 permit
121.244.91.52 permit
122.15.156.182 permit
123.126.78.64/29 permit 123.126.78.64/29 permit
124.108.96.24/31 permit 124.108.96.24/31 permit
124.108.96.28/31 permit 124.108.96.28/31 permit
@@ -1337,6 +1339,8 @@
130.61.9.72 permit 130.61.9.72 permit
130.162.39.83 permit 130.162.39.83 permit
130.211.0.0/22 permit 130.211.0.0/22 permit
130.248.172.0/24 permit
130.248.173.0/24 permit
131.253.30.0/24 permit 131.253.30.0/24 permit
131.253.121.0/26 permit 131.253.121.0/26 permit
132.145.13.209 permit 132.145.13.209 permit
@@ -1348,19 +1352,7 @@
134.170.141.64/26 permit 134.170.141.64/26 permit
134.170.143.0/24 permit 134.170.143.0/24 permit
134.170.174.0/24 permit 134.170.174.0/24 permit
135.84.80.0/24 permit
135.84.81.0/24 permit
135.84.82.0/24 permit
135.84.83.0/24 permit
135.84.216.0/22 permit 135.84.216.0/22 permit
136.143.160.0/24 permit
136.143.161.0/24 permit
136.143.162.0/24 permit
136.143.178.49 permit
136.143.182.0/23 permit
136.143.184.0/24 permit
136.143.188.0/24 permit
136.143.190.0/23 permit
136.147.128.0/20 permit 136.147.128.0/20 permit
136.147.135.0/24 permit 136.147.135.0/24 permit
136.147.176.0/20 permit 136.147.176.0/20 permit
@@ -1375,7 +1367,6 @@
139.138.46.219 permit 139.138.46.219 permit
139.138.57.55 permit 139.138.57.55 permit
139.138.58.119 permit 139.138.58.119 permit
139.167.79.86 permit
139.180.17.0/24 permit 139.180.17.0/24 permit
140.238.148.191 permit 140.238.148.191 permit
141.148.159.229 permit 141.148.159.229 permit
@@ -1410,6 +1401,7 @@
146.20.215.0/24 permit 146.20.215.0/24 permit
146.20.215.182 permit 146.20.215.182 permit
146.88.28.0/24 permit 146.88.28.0/24 permit
147.154.32.0/25 permit
147.243.1.47 permit 147.243.1.47 permit
147.243.1.48 permit 147.243.1.48 permit
147.243.1.153 permit 147.243.1.153 permit
@@ -1450,7 +1442,6 @@
157.151.208.65 permit 157.151.208.65 permit
157.255.1.64/29 permit 157.255.1.64/29 permit
158.101.211.207 permit 158.101.211.207 permit
158.120.80.0/21 permit
158.247.16.0/20 permit 158.247.16.0/20 permit
159.92.154.0/24 permit 159.92.154.0/24 permit
159.92.155.0/24 permit 159.92.155.0/24 permit
@@ -1478,6 +1469,11 @@
161.38.204.0/22 permit 161.38.204.0/22 permit
161.71.32.0/19 permit 161.71.32.0/19 permit
161.71.64.0/20 permit 161.71.64.0/20 permit
162.88.4.0/23 permit
162.88.8.0/24 permit
162.88.24.0/24 permit
162.88.25.0/24 permit
162.88.36.0/24 permit
162.247.216.0/22 permit 162.247.216.0/22 permit
163.47.180.0/22 permit 163.47.180.0/22 permit
163.114.130.16 permit 163.114.130.16 permit
@@ -1486,7 +1482,6 @@
163.114.135.16 permit 163.114.135.16 permit
164.152.23.32 permit 164.152.23.32 permit
164.177.132.168/30 permit 164.177.132.168/30 permit
165.173.128.0/24 permit
166.78.68.0/22 permit 166.78.68.0/22 permit
166.78.68.221 permit 166.78.68.221 permit
166.78.69.169 permit 166.78.69.169 permit
@@ -1515,12 +1510,6 @@
168.245.12.252 permit 168.245.12.252 permit
168.245.46.9 permit 168.245.46.9 permit
168.245.127.231 permit 168.245.127.231 permit
169.148.129.0/24 permit
169.148.131.0/24 permit
169.148.142.10 permit
169.148.144.0/25 permit
169.148.144.10 permit
170.10.68.0/22 permit
170.10.128.0/24 permit 170.10.128.0/24 permit
170.10.129.0/24 permit 170.10.129.0/24 permit
170.10.132.56/29 permit 170.10.132.56/29 permit
@@ -1561,6 +1550,7 @@
183.240.219.64/29 permit 183.240.219.64/29 permit
185.4.120.0/22 permit 185.4.120.0/22 permit
185.12.80.0/22 permit 185.12.80.0/22 permit
185.28.196.0/22 permit
185.58.84.93 permit 185.58.84.93 permit
185.80.93.204 permit 185.80.93.204 permit
185.80.93.227 permit 185.80.93.227 permit
@@ -1626,6 +1616,8 @@
192.18.139.154 permit 192.18.139.154 permit
192.18.145.36 permit 192.18.145.36 permit
192.18.152.58 permit 192.18.152.58 permit
192.28.128.0/18 permit
192.29.103.128/25 permit
192.30.252.0/22 permit 192.30.252.0/22 permit
192.161.144.0/20 permit 192.161.144.0/20 permit
192.162.87.0/24 permit 192.162.87.0/24 permit
@@ -1651,14 +1643,6 @@
195.234.109.226 permit 195.234.109.226 permit
195.245.230.0/23 permit 195.245.230.0/23 permit
198.2.128.0/18 permit 198.2.128.0/18 permit
198.2.128.0/24 permit
198.2.132.0/22 permit
198.2.136.0/23 permit
198.2.145.0/24 permit
198.2.177.0/24 permit
198.2.178.0/23 permit
198.2.180.0/24 permit
198.2.186.0/23 permit
198.21.0.0/21 permit 198.21.0.0/21 permit
198.37.144.0/20 permit 198.37.144.0/20 permit
198.37.152.186 permit 198.37.152.186 permit
@@ -1673,20 +1657,13 @@
198.244.60.0/22 permit 198.244.60.0/22 permit
198.245.80.0/20 permit 198.245.80.0/20 permit
198.245.81.0/24 permit 198.245.81.0/24 permit
199.15.212.0/22 permit
199.15.213.187 permit 199.15.213.187 permit
199.15.226.37 permit 199.15.226.37 permit
199.16.156.0/22 permit 199.16.156.0/22 permit
199.33.145.1 permit 199.33.145.1 permit
199.33.145.32 permit 199.33.145.32 permit
199.34.22.36 permit
199.59.148.0/22 permit 199.59.148.0/22 permit
199.67.80.2 permit
199.67.80.20 permit
199.67.82.2 permit
199.67.82.20 permit
199.67.84.0/24 permit
199.67.86.0/24 permit
199.67.88.0/24 permit
199.101.161.130 permit 199.101.161.130 permit
199.101.162.0/25 permit 199.101.162.0/25 permit
199.122.120.0/21 permit 199.122.120.0/21 permit
@@ -1698,7 +1675,6 @@
202.165.102.47 permit 202.165.102.47 permit
202.177.148.100 permit 202.177.148.100 permit
202.177.148.110 permit 202.177.148.110 permit
203.31.36.0/22 permit
203.32.4.25 permit 203.32.4.25 permit
203.55.21.0/24 permit 203.55.21.0/24 permit
203.81.17.0/24 permit 203.81.17.0/24 permit
@@ -1744,19 +1720,13 @@
204.92.114.187 permit 204.92.114.187 permit
204.92.114.203 permit 204.92.114.203 permit
204.92.114.204/31 permit 204.92.114.204/31 permit
204.141.32.0/23 permit
204.141.42.0/23 permit
204.220.160.0/21 permit 204.220.160.0/21 permit
204.220.168.0/21 permit 204.220.168.0/21 permit
204.220.176.0/20 permit 204.220.176.0/20 permit
204.232.168.0/24 permit 204.232.168.0/24 permit
205.139.110.0/24 permit 205.139.110.0/24 permit
205.201.128.0/20 permit 205.201.128.0/20 permit
205.201.131.128/25 permit
205.201.134.128/25 permit
205.201.136.0/23 permit
205.201.137.229 permit 205.201.137.229 permit
205.201.139.0/24 permit
205.207.104.0/22 permit 205.207.104.0/22 permit
205.220.167.17 permit 205.220.167.17 permit
205.220.167.98 permit 205.220.167.98 permit
@@ -1784,7 +1754,6 @@
207.46.132.128/27 permit 207.46.132.128/27 permit
207.46.198.0/25 permit 207.46.198.0/25 permit
207.46.200.0/27 permit 207.46.200.0/27 permit
207.58.147.64/28 permit
207.67.38.0/24 permit 207.67.38.0/24 permit
207.67.98.192/27 permit 207.67.98.192/27 permit
207.68.176.0/26 permit 207.68.176.0/26 permit
@@ -1831,6 +1800,8 @@
208.74.204.5 permit 208.74.204.5 permit
208.74.204.9 permit 208.74.204.9 permit
208.75.120.0/22 permit 208.75.120.0/22 permit
208.76.62.0/24 permit
208.76.63.0/24 permit
208.82.237.96/29 permit 208.82.237.96/29 permit
208.82.237.104/31 permit 208.82.237.104/31 permit
208.82.238.96/29 permit 208.82.238.96/29 permit
@@ -1930,7 +1901,6 @@
213.199.177.0/26 permit 213.199.177.0/26 permit
216.17.150.242 permit 216.17.150.242 permit
216.17.150.251 permit 216.17.150.251 permit
216.22.15.224/27 permit
216.24.224.0/20 permit 216.24.224.0/20 permit
216.39.60.154/31 permit 216.39.60.154/31 permit
216.39.60.156/30 permit 216.39.60.156/30 permit
@@ -1973,7 +1943,10 @@
216.136.162.65 permit 216.136.162.65 permit
216.136.162.120/29 permit 216.136.162.120/29 permit
216.136.168.80/28 permit 216.136.168.80/28 permit
216.139.64.0/19 permit
216.145.221.0/24 permit 216.145.221.0/24 permit
216.146.32.0/24 permit
216.146.33.0/24 permit
216.198.0.0/18 permit 216.198.0.0/18 permit
216.203.30.55 permit 216.203.30.55 permit
216.203.33.178/31 permit 216.203.33.178/31 permit
@@ -1999,8 +1972,6 @@
2603:1030:20e:3::23c permit 2603:1030:20e:3::23c permit
2603:1030:b:3::152 permit 2603:1030:b:3::152 permit
2603:1030:c02:8::14 permit 2603:1030:c02:8::14 permit
2607:13c0:0001:0000:0000:0000:0000:7000/116 permit
2607:13c0:0002:0000:0000:0000:0000:1000/116 permit
2607:f8b0:4000::/36 permit 2607:f8b0:4000::/36 permit
2620:109:c003:104::/64 permit 2620:109:c003:104::/64 permit
2620:109:c003:104::215 permit 2620:109:c003:104::215 permit
+12
View File
@@ -0,0 +1,12 @@
#!/bin/sh
cat <<EOF > /redis.conf
requirepass $REDISPASS
user quota_notify on nopass ~QW_* -@all +get +hget +ping
EOF
if [ -n "$REDISMASTERPASS" ]; then
echo "masterauth $REDISMASTERPASS" >> /redis.conf
fi
exec redis-server /redis.conf
+1
View File
@@ -25,6 +25,7 @@ catch (PDOException $e) {
// Init Redis // Init Redis
$redis = new Redis(); $redis = new Redis();
$redis->connect('redis-mailcow', 6379); $redis->connect('redis-mailcow', 6379);
$redis->auth(getenv("REDISPASS"));
function parse_email($email) { function parse_email($email) {
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false; if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
@@ -4,6 +4,7 @@ ini_set('error_reporting', 0);
$redis = new Redis(); $redis = new Redis();
$redis->connect('redis-mailcow', 6379); $redis->connect('redis-mailcow', 6379);
$redis->auth(getenv("REDISPASS"));
function in_net($addr, $net) { function in_net($addr, $net) {
$net = explode('/', $net); $net = explode('/', $net);
+1
View File
@@ -3,6 +3,7 @@ dns {
} }
map_watch_interval = 30s; map_watch_interval = 30s;
task_timeout = 30s; task_timeout = 30s;
enable_mime_utf = true;
disable_monitoring = true; disable_monitoring = true;
# In case a task times out (like DNS lookup), soft reject the message # In case a task times out (like DNS lookup), soft reject the message
# instead of silently accepting the message without further processing. # instead of silently accepting the message without further processing.
+1
View File
@@ -24,6 +24,7 @@ catch (PDOException $e) {
// Init Redis // Init Redis
$redis = new Redis(); $redis = new Redis();
$redis->connect('redis-mailcow', 6379); $redis->connect('redis-mailcow', 6379);
$redis->auth(getenv("REDISPASS"));
// Functions // Functions
function parse_email($email) { function parse_email($email) {
@@ -14,6 +14,7 @@ try {
else { else {
$redis->connect('redis-mailcow', 6379); $redis->connect('redis-mailcow', 6379);
} }
$redis->auth(getenv("REDISPASS"));
} }
catch (Exception $e) { catch (Exception $e) {
exit; exit;
@@ -24,6 +24,7 @@ catch (PDOException $e) {
// Init Redis // Init Redis
$redis = new Redis(); $redis = new Redis();
$redis->connect('redis-mailcow', 6379); $redis->connect('redis-mailcow', 6379);
$redis->auth(getenv("REDISPASS"));
// Functions // Functions
function parse_email($email) { function parse_email($email) {
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

+44
View File
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY st0 "fill:#50BD37;">
]>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="640px" height="350px" viewBox="78.712 58.488 640 350" style="enable-background:new 78.712 58.488 640 350;"
xml:space="preserve">
<path style="&st0;" d="M648.541,145.679c-9.947,0-17.009-7.278-17.009-17.048c0-9.777,7.062-17.057,17.009-17.057
c10.024,0,17.086,7.279,17.086,17.057C665.627,138.401,658.565,145.679,648.541,145.679z M648.511,94.893
c-19.693,0-33.679,14.4-33.679,33.738c0,19.33,13.985,33.729,33.679,33.729c19.822,0,33.808-14.4,33.808-33.729
C682.318,109.293,668.333,94.893,648.511,94.893z M648.482,179.843c-29.889,0-51.123-21.868-51.123-51.212
c0-29.353,21.234-51.209,51.123-51.209c30.082,0,51.307,21.856,51.307,51.209C699.789,157.975,678.564,179.843,648.482,179.843z
M648.442,58.488c-40.929,0-69.995,29.946-69.995,70.143c0,40.189,29.066,70.125,69.995,70.125c41.194,0,70.27-29.937,70.27-70.125
C718.712,88.434,689.637,58.488,648.442,58.488z M158.166,183.902l-21.018-5.008c-19.131-4.396-28.849-9.413-28.849-23.21
c0-15.684,15.99-21.965,30.419-21.965c14.667,0,25.382,7.329,31.693,18.737c0.02,0.048,0.051,0.097,0.09,0.157
c0.127,0.247,0.276,0.484,0.403,0.731l0.03-0.02c1.985,3.002,5.323,5.008,8.919,5.008c6.122,0,10.558-4.425,10.558-10.547
c0-2.341-0.504-4.82-1.601-6.688c-10.764-18.302-28.513-26.192-48.838-26.192c-27.594,0-54.262,13.797-54.262,44.218
c0,27.921,27.605,36.079,37.64,38.578l20.069,4.71c15.368,3.763,27.912,8.791,27.912,23.517c0,16.938-17.561,23.943-34.499,23.943
c-17.245,0-30.015-9.37-38.814-22.37h-0.01c-1.956-3-4.988-4.328-8.702-4.328c-5.984,0-10.805,5.185-10.587,11.162
c0.098,2.438,0.909,4.637,2.153,6.405c13.787,20.633,33.728,28.41,55.96,28.41c28.543,0,57.085-13.143,57.085-45.132
C193.918,203.325,178.551,188.613,158.166,183.902z M298.479,250.312c-33.866,0-55.199-25.403-55.199-58.331
c0-32.939,21.333-58.343,55.199-58.343c34.192,0,55.516,25.403,55.516,58.343C353.996,224.91,332.672,250.312,298.479,250.312z
M298.479,114.823c-45.471,0-77.777,32.93-77.777,77.158c0,44.217,32.306,77.146,77.777,77.146
c45.786,0,78.093-32.929,78.093-77.146C376.572,147.753,344.266,114.823,298.479,114.823z M518.715,234.312
c-0.771,0.74-1.549,1.472-2.399,2.175c-1.106,1.014-2.391,2.112-3.854,3.208c-8.829,6.391-19.979,10.094-33.017,10.094
c-33.876,0-55.198-25.402-55.198-58.332c0-32.939,21.322-58.342,55.198-58.342c34.183,0,55.506,25.403,55.506,58.342
C534.951,208.653,529.135,223.774,518.715,234.312z M468.097,317.938c2.528,0,5.146-0.168,7.863-0.504
c5.018-0.631,9.588-0.909,13.729-0.909c19.24,0.109,29.036,5.7,34.943,12.158c5.895,6.499,8.168,15.311,8.158,22.796
c0.01,3.586-0.555,6.795-1.177,8.721c-2.944,8.93-8.888,15.002-17.996,19.576c-9.035,4.484-21.095,6.777-33.707,6.757
c-4.514,0-9.105-0.288-13.639-0.831c-8.573-0.987-19.911-4.671-28.13-11.093c-4.138-3.199-6.458-6.991-8.858-11.485
c-2.379-4.514-2.783-9.748-2.783-16.442v-0.742c0-12.346,4.84-20.544,11.051-26.5c3.07-2.904,5.69-5.064,7.99-6.438
c0.366-0.218,0.438-0.416,0.755-0.593C452.39,316.014,459.684,317.968,468.097,317.938z M479.445,114.301
c-45.471,0-77.786,32.929-77.786,77.157c0,29.887,14.765,54.598,38.378,67.489c-0.314,0.314-0.621,0.641-0.916,0.966
c-6.104,6.687-9.226,15.25-9.236,23.913c-0.008,3.821,0.624,7.741,1.977,11.494c-3.062,1.956-6.717,4.634-10.46,8.147
c-9.026,8.408-18.734,22.541-19.021,42.097c-0.01,0.454-0.01,0.829-0.01,1.118c-0.01,10.071,2.379,19.157,6.459,26.774
c6.133,11.466,15.683,19.445,25.539,24.77c9.917,5.334,20.257,8.166,29.273,9.274c5.373,0.643,10.826,0.988,16.268,0.988
c15.151-0.02,30.261-2.578,43.409-9.019c13.085-6.34,24.333-17.253,29.192-32.562c1.443-4.553,2.212-9.719,2.231-15.428
c-0.02-11.595-3.349-25.759-13.767-37.452c-10.421-11.734-27.654-19.566-51.288-19.459c-5.138,0-10.606,0.356-16.426,1.078
c-1.877,0.227-3.596,0.334-5.166,0.334c-7.239-0.048-10.872-2.053-13.036-4.098c-2.133-2.084-3.2-4.839-3.229-8.058
c-0.01-3.28,1.284-6.727,3.467-9.078c2.231-2.332,5.008-3.91,9.846-3.97c0.436,0,0.9,0.01,1.374,0.05
c3.101,0.216,6.112,0.325,9.037,0.325c24.188,0.047,42.38-7.448,54.756-17.759c12.415-10.312,18.971-22.854,22.071-32.76l-0.04-0.01
c3.37-8.899,5.197-18.715,5.197-29.166C557.539,147.229,525.234,114.301,479.445,114.301z"/>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY st0 "fill:#50BD37;">
]>
<svg version="1.1" id="SOGo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="140.263px" height="140.269px" viewBox="499.737 0 140.263 140.269"
style="enable-background:new 499.737 0 140.263 140.269;" xml:space="preserve">
<path style="&st0;" d="M569.697,87.024c-9.928,0-16.975-7.264-16.975-17.017c0-9.757,7.047-17.022,16.975-17.022
c10.006,0,17.054,7.265,17.054,17.022C586.751,79.76,579.703,87.024,569.697,87.024z M569.667,36.335
c-19.657,0-33.614,14.372-33.614,33.673c0,19.294,13.955,33.667,33.614,33.667c19.787,0,33.745-14.372,33.745-33.667
C603.411,50.707,589.454,36.335,569.667,36.335z M569.639,121.123c-29.833,0-51.025-21.825-51.025-51.115
c0-29.296,21.192-51.111,51.025-51.111c30.025,0,51.213,21.815,51.213,51.111C620.852,99.298,599.664,121.123,569.639,121.123z
M569.602,0c-40.854,0-69.864,29.889-69.864,70.007c0,40.112,29.01,69.993,69.864,69.993c41.116,0,70.136-29.88,70.136-69.993
C639.737,29.889,610.719,0,569.602,0z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+3
View File
@@ -16,6 +16,9 @@
SOGoFoldersSendEMailNotifications = YES; SOGoFoldersSendEMailNotifications = YES;
SOGoForwardEnabled = YES; SOGoForwardEnabled = YES;
// Fixes "MODIFICATION_FAILED" error (HTTP 412) in Clients when accepting invitations from external services
SOGoDisableOrganizerEventCheck = YES;
// Option to set Users as admin to globally manage calendar permissions etc. Disabled by default // Option to set Users as admin to globally manage calendar permissions etc. Disabled by default
// SOGoSuperUsernames = ("moo@example.com"); // SOGoSuperUsernames = ("moo@example.com");
+1
View File
@@ -7,6 +7,7 @@ try {
else { else {
$redis->connect('redis-mailcow', 6379); $redis->connect('redis-mailcow', 6379);
} }
$redis->auth(getenv("REDISPASS"));
} }
catch (Exception $e) { catch (Exception $e) {
exit; exit;
+1 -1
View File
@@ -104,7 +104,7 @@ $template_data = [
'all_domains' => $all_domains, 'all_domains' => $all_domains,
'mailboxes' => $mailboxes, 'mailboxes' => $mailboxes,
'f2b_data' => $f2b_data, 'f2b_data' => $f2b_data,
'f2b_banlist_url' => getBaseUrl() . "/api/v1/get/fail2ban/banlist/" . $f2b_data['banlist_id'], 'f2b_banlist_url' => getBaseUrl() . "/f2b-banlist?id=" . $f2b_data['banlist_id'],
'q_data' => quarantine('settings'), 'q_data' => quarantine('settings'),
'qn_data' => quota_notification('get'), 'qn_data' => quota_notification('get'),
'pw_reset_data' => reset_password('get_notification'), 'pw_reset_data' => reset_password('get_notification'),
+3 -30
View File
@@ -1531,6 +1531,9 @@ paths:
port1: port1:
description: the smtp port of the target mail server description: the smtp port of the target mail server
type: string type: string
user1:
description: the username of the mailbox
type: string
password: password:
description: the password of the mailbox description: the password of the mailbox
type: string type: string
@@ -5415,12 +5418,6 @@ paths:
started_at: "2019-12-22T20:59:58.382274592Z" started_at: "2019-12-22T20:59:58.382274592Z"
state: running state: running
type: info type: info
solr-mailcow:
container: solr-mailcow
image: "mailcow/solr:1.7"
started_at: "2019-12-22T20:59:59.635413798Z"
state: running
type: info
unbound-mailcow: unbound-mailcow:
container: unbound-mailcow container: unbound-mailcow
image: "mailcow/unbound:1.10" image: "mailcow/unbound:1.10"
@@ -5442,30 +5439,6 @@ paths:
hey where started and a few other details. hey where started and a few other details.
operationId: Get container status operationId: Get container status
summary: Get container status summary: Get container status
/api/v1/get/status/solr:
get:
responses:
"401":
$ref: "#/components/responses/Unauthorized"
"200":
content:
application/json:
examples:
response:
value:
solr_documents: null
solr_enabled: false
solr_size: null
type: info
description: OK
headers: {}
tags:
- Status
description: >-
Using this endpoint you can get the status of all containers and when
hey where started and a few other details.
operationId: Get solr status
summary: Get solr status
/api/v1/get/status/vmail: /api/v1/get/status/vmail:
get: get:
responses: responses:
+1
View File
@@ -16,6 +16,7 @@ try {
else { else {
$redis->connect('redis-mailcow', 6379); $redis->connect('redis-mailcow', 6379);
} }
$redis->auth(getenv("REDISPASS"));
} }
catch (Exception $e) { catch (Exception $e) {
exit; exit;
-4
View File
@@ -8,7 +8,6 @@ if (!isset($_SESSION['mailcow_cc_role']) || $_SESSION['mailcow_cc_role'] != "adm
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/header.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/header.inc.php';
$_SESSION['return_to'] = $_SERVER['REQUEST_URI']; $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
$solr_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_SOLR"])) ? false : solr_status();
$clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ? false : true; $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ? false : true;
@@ -25,7 +24,6 @@ $vmail_df = explode(',', (string)json_decode(docker('post', 'dovecot-mailcow', '
// containers // containers
$containers_info = (array) docker('info'); $containers_info = (array) docker('info');
if ($clamd_status === false) unset($containers_info['clamd-mailcow']); if ($clamd_status === false) unset($containers_info['clamd-mailcow']);
if ($solr_status === false) unset($containers_info['solr-mailcow']);
ksort($containers_info); ksort($containers_info);
$containers = array(); $containers = array();
foreach ($containers_info as $container => $container_info) { foreach ($containers_info as $container => $container_info) {
@@ -69,8 +67,6 @@ $template_data = [
'timezone' => $timezone, 'timezone' => $timezone,
'gal' => @$_SESSION['gal'], 'gal' => @$_SESSION['gal'],
'license_guid' => license('guid'), 'license_guid' => license('guid'),
'solr_status' => $solr_status,
'solr_uptime' => round($solr_status['status']['dovecot-fts']['uptime'] / 1000 / 60 / 60),
'clamd_status' => $clamd_status, 'clamd_status' => $clamd_status,
'containers' => $containers, 'containers' => $containers,
'ip_check' => customize('get', 'ip_check'), 'ip_check' => customize('get', 'ip_check'),
+3
View File
@@ -166,6 +166,9 @@ if (isset($_SESSION['mailcow_cc_role'])) {
if (substr($result['recipient_map_old'], 0, 1) == '@') { if (substr($result['recipient_map_old'], 0, 1) == '@') {
$result['recipient_map_old'] = substr($result['recipient_map_old'], 1); $result['recipient_map_old'] = substr($result['recipient_map_old'], 1);
} }
if (substr($result['recipient_map_new'], 0, 1) == '@') {
$result['recipient_map_new'] = substr($result['recipient_map_new'], 1);
}
$template = 'edit/recipient_map.twig'; $template = 'edit/recipient_map.twig';
$template_data = ['map' => $map]; $template_data = ['map' => $map];
} }
+11
View File
@@ -0,0 +1,11 @@
<?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
if (isset($_GET['id'])) {
header('Content-Type: text/plain');
echo fail2ban('banlist', 'get', $_GET['id']);
} else {
header('HTTP/1.1 404 Not Found');
exit;
}
+3 -3
View File
@@ -4,14 +4,14 @@ header('Content-Type: application/json');
if (!isset($_SESSION['mailcow_cc_role'])) { if (!isset($_SESSION['mailcow_cc_role'])) {
exit(); exit();
} }
if (isset($_GET['script'])) { if (isset($_REQUEST['script'])) {
$sieve = new Sieve\SieveParser(); $sieve = new Sieve\SieveParser();
try { try {
if (empty($_GET['script'])) { if (empty($_REQUEST['script'])) {
echo json_encode(array('type' => 'danger', 'msg' => $lang['danger']['script_empty'])); echo json_encode(array('type' => 'danger', 'msg' => $lang['danger']['script_empty']));
exit(); exit();
} }
$sieve->parse($_GET['script']); $sieve->parse($_REQUEST['script']);
} }
catch (Exception $e) { catch (Exception $e) {
echo json_encode(array('type' => 'danger', 'msg' => $e->getMessage())); echo json_encode(array('type' => 'danger', 'msg' => $e->getMessage()));
@@ -270,6 +270,9 @@ function recipient_map($_action, $_data = null, $attr = null) {
$old_dest = substr($old_dest, 1); $old_dest = substr($old_dest, 1);
} }
$new_dest = strtolower(trim($_data['recipient_map_new'])); $new_dest = strtolower(trim($_data['recipient_map_new']));
if (substr($new_dest, 0, 1) == '@') {
$new_dest = substr($new_dest, 1);
}
$active = intval($_data['active']); $active = intval($_data['active']);
if (is_valid_domain_name($old_dest)) { if (is_valid_domain_name($old_dest)) {
$old_dest_sane = '@' . idn_to_ascii($old_dest, 0, INTL_IDNA_VARIANT_UTS46); $old_dest_sane = '@' . idn_to_ascii($old_dest, 0, INTL_IDNA_VARIANT_UTS46);
@@ -285,7 +288,13 @@ function recipient_map($_action, $_data = null, $attr = null) {
); );
return false; return false;
} }
if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) { if (is_valid_domain_name($new_dest)) {
$new_dest_sane = '@' . idn_to_ascii($new_dest, 0, INTL_IDNA_VARIANT_UTS46);
}
elseif (filter_var($new_dest, FILTER_VALIDATE_EMAIL)) {
$new_dest_sane = $new_dest;
}
else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
@@ -308,7 +317,7 @@ function recipient_map($_action, $_data = null, $attr = null) {
(:old_dest, :new_dest, :active)"); (:old_dest, :new_dest, :active)");
$stmt->execute(array( $stmt->execute(array(
':old_dest' => $old_dest_sane, ':old_dest' => $old_dest_sane,
':new_dest' => $new_dest, ':new_dest' => $new_dest_sane,
':active' => $active ':active' => $active
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
@@ -325,6 +334,9 @@ function recipient_map($_action, $_data = null, $attr = null) {
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
$new_dest = (!empty($_data['recipient_map_new'])) ? $_data['recipient_map_new'] : $is_now['recipient_map_new']; $new_dest = (!empty($_data['recipient_map_new'])) ? $_data['recipient_map_new'] : $is_now['recipient_map_new'];
$old_dest = (!empty($_data['recipient_map_old'])) ? $_data['recipient_map_old'] : $is_now['recipient_map_old']; $old_dest = (!empty($_data['recipient_map_old'])) ? $_data['recipient_map_old'] : $is_now['recipient_map_old'];
if (substr($new_dest, 0, 1) == '@') {
$new_dest = substr($new_dest, 1);
}
if (substr($old_dest, 0, 1) == '@') { if (substr($old_dest, 0, 1) == '@') {
$old_dest = substr($old_dest, 1); $old_dest = substr($old_dest, 1);
} }
@@ -351,7 +363,13 @@ function recipient_map($_action, $_data = null, $attr = null) {
); );
continue; continue;
} }
if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) { if (is_valid_domain_name($new_dest)) {
$new_dest_sane = '@' . idn_to_ascii($new_dest, 0, INTL_IDNA_VARIANT_UTS46);
}
elseif (filter_var($new_dest, FILTER_VALIDATE_EMAIL)) {
$new_dest_sane = $new_dest;
}
else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
@@ -378,7 +396,7 @@ function recipient_map($_action, $_data = null, $attr = null) {
WHERE `id`= :id"); WHERE `id`= :id");
$stmt->execute(array( $stmt->execute(array(
':old_dest' => $old_dest_sane, ':old_dest' => $old_dest_sane,
':new_dest' => $new_dest, ':new_dest' => $new_dest_sane,
':active' => $active, ':active' => $active,
':id' => $id ':id' => $id
)); ));
+2 -2
View File
@@ -26,7 +26,7 @@ function dkim($_action, $_data = null, $privkey = false) {
); );
continue; continue;
} }
if (!ctype_alnum(str_replace(['-', '_'], '', $dkim_selector))) { if (!ctype_alnum(str_replace(['-', '_', '.'], '', $dkim_selector))) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
@@ -188,7 +188,7 @@ function dkim($_action, $_data = null, $privkey = false) {
return false; return false;
} }
} }
if (!ctype_alnum($dkim_selector)) { if (!ctype_alnum(str_replace(['-', '_', '.'], '', $dkim_selector))) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
+23 -49
View File
@@ -1174,7 +1174,7 @@ function user_get_alias_details($username) {
AND `goto` != :username_goto2 AND `goto` != :username_goto2
AND `address` != :username_address"); AND `address` != :username_address");
$stmt->execute(array( $stmt->execute(array(
':username_goto' => '(^|,)'.$username.'($|,)', ':username_goto' => '(^|,)'.preg_quote($username, '/').'($|,)',
':username_goto2' => $username, ':username_goto2' => $username,
':username_address' => $username ':username_address' => $username
)); ));
@@ -1222,7 +1222,7 @@ function user_get_alias_details($username) {
$data['aliases_send_as_all'] = $row['send_as']; $data['aliases_send_as_all'] = $row['send_as'];
} }
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '') as `address` FROM `alias` WHERE `goto` REGEXP :username AND `address` LIKE '@%';"); $stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '') as `address` FROM `alias` WHERE `goto` REGEXP :username AND `address` LIKE '@%';");
$stmt->execute(array(':username' => '(^|,)'.$username.'($|,)')); $stmt->execute(array(':username' => '(^|,)'.preg_quote($username, '/').'($|,)'));
$run = $stmt->fetchAll(PDO::FETCH_ASSOC); $run = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($run)) { while ($row = array_shift($run)) {
$data['is_catch_all'] = $row['address']; $data['is_catch_all'] = $row['address'];
@@ -2275,9 +2275,25 @@ function cors($action, $data = null) {
break; break;
} }
} }
function getBaseURL() { function getBaseURL($protocol = null) {
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http'; // Get current server name
$host = $_SERVER['HTTP_HOST']; $host = strtolower($_SERVER['SERVER_NAME']);
// craft allowed server name list
$mailcow_hostname = strtolower(getenv("MAILCOW_HOSTNAME"));
$additional_server_names = strtolower(getenv("ADDITIONAL_SERVER_NAMES")) ?: "";
$additional_server_names = preg_replace('/\s+/', '', $additional_server_names);
$allowed_server_names = $additional_server_names !== "" ? explode(',', $additional_server_names) : array();
array_push($allowed_server_names, $mailcow_hostname);
// Fallback to MAILCOW HOSTNAME if current server name is not in allowed list
if (!in_array($host, $allowed_server_names)) {
$host = $mailcow_hostname;
}
if (!isset($protocol)) {
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
}
$base_url = $protocol . '://' . $host; $base_url = $protocol . '://' . $host;
return $base_url; return $base_url;
@@ -2515,6 +2531,8 @@ function reset_password($action, $data = null) {
':username' => $username ':username' => $username
)); ));
update_sogo_static_view($username);
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $action, $_data_log), 'log' => array(__FUNCTION__, $action, $_data_log),
@@ -2906,50 +2924,6 @@ function getGUID() {
.substr($charid,16, 4).$hyphen .substr($charid,16, 4).$hyphen
.substr($charid,20,12); .substr($charid,20,12);
} }
function solr_status() {
$curl = curl_init();
$endpoint = 'http://solr:8983/solr/admin/cores';
$params = array(
'action' => 'STATUS',
'core' => 'dovecot-fts',
'indexInfo' => 'true'
);
$url = $endpoint . '?' . http_build_query($params);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 0);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
$response_core = curl_exec($curl);
if ($response_core === false) {
$err = curl_error($curl);
curl_close($curl);
return false;
}
else {
curl_close($curl);
$curl = curl_init();
$status_core = json_decode($response_core, true);
$url = 'http://solr:8983/solr/admin/info/system';
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 0);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
$response_sysinfo = curl_exec($curl);
if ($response_sysinfo === false) {
$err = curl_error($curl);
curl_close($curl);
return false;
}
else {
curl_close($curl);
$status_sysinfo = json_decode($response_sysinfo, true);
$status = array_merge($status_core, $status_sysinfo);
return (!empty($status['status']['dovecot-fts']) && !empty($status['jvm']['memory'])) ? $status : false;
}
return (!empty($status['status']['dovecot-fts'])) ? $status['status']['dovecot-fts'] : false;
}
return false;
}
function cleanupJS($ignore = '', $folder = '/tmp/*.js') { function cleanupJS($ignore = '', $folder = '/tmp/*.js') {
$now = time(); $now = time();
+13 -24
View File
@@ -48,6 +48,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$_data["validity"] = 8760; $_data["validity"] = 8760;
} }
$domain = $_data['domain']; $domain = $_data['domain'];
$description = $_data['description'];
$valid_domains[] = mailbox('get', 'mailbox_details', $username)['domain']; $valid_domains[] = mailbox('get', 'mailbox_details', $username)['domain'];
$valid_alias_domains = user_get_alias_details($username)['alias_domains']; $valid_alias_domains = user_get_alias_details($username)['alias_domains'];
if (!empty($valid_alias_domains)) { if (!empty($valid_alias_domains)) {
@@ -62,10 +63,11 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
return false; return false;
} }
$validity = strtotime("+" . $_data["validity"] . " hour"); $validity = strtotime("+" . $_data["validity"] . " hour");
$stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `goto`, `validity`) VALUES $stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `description`, `goto`, `validity`) VALUES
(:address, :goto, :validity)"); (:address, :description, :goto, :validity)");
$stmt->execute(array( $stmt->execute(array(
':address' => readable_random_string(rand(rand(3, 9), rand(3, 9))) . '.' . readable_random_string(rand(rand(3, 9), rand(3, 9))) . '@' . $domain, ':address' => readable_random_string(rand(rand(3, 9), rand(3, 9))) . '.' . readable_random_string(rand(rand(3, 9), rand(3, 9))) . '@' . $domain,
':description' => $description,
':goto' => $username, ':goto' => $username,
':validity' => $validity ':validity' => $validity
)); ));
@@ -3351,7 +3353,12 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
'old_maildir' => $domain . '/' . $old_local_part, 'old_maildir' => $domain . '/' . $old_local_part,
'new_maildir' => $domain . '/' . $new_local_part 'new_maildir' => $domain . '/' . $new_local_part
); );
docker('post', 'dovecot-mailcow', 'exec', $exec_fields); if (getenv("CLUSTERMODE") == "replication") {
// broadcast to each dovecot container
docker('broadcast', 'dovecot-mailcow', 'exec', $exec_fields);
} else {
docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
}
// rename username in sogo // rename username in sogo
$exec_fields = array( $exec_fields = array(
@@ -3763,7 +3770,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$data['external_sender_aliases'] = array(); $data['external_sender_aliases'] = array();
// Fixed addresses // Fixed addresses
$stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `goto` REGEXP :goto AND `address` NOT LIKE '@%'"); $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `goto` REGEXP :goto AND `address` NOT LIKE '@%'");
$stmt->execute(array(':goto' => '(^|,)'.$_data.'($|,)')); $stmt->execute(array(':goto' => '(^|,)'.preg_quote($_data, '/').'($|,)'));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($rows)) { while ($row = array_shift($rows)) {
$data['fixed_sender_aliases'][] = $row['address']; $data['fixed_sender_aliases'][] = $row['address'];
@@ -4196,6 +4203,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
} }
$stmt = $pdo->prepare("SELECT `address`, $stmt = $pdo->prepare("SELECT `address`,
`goto`, `goto`,
`description`,
`validity`, `validity`,
`created`, `created`,
`modified` `modified`
@@ -5429,25 +5437,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
'msg' => 'Could not move maildir to garbage collector: variables local_part and/or domain empty' 'msg' => 'Could not move maildir to garbage collector: variables local_part and/or domain empty'
); );
} }
if (strtolower(getenv('SKIP_SOLR')) == 'n' && strtolower(getenv('FLATCURVE_EXPERIMENTAL')) != 'y') {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://solr:8983/solr/dovecot-fts/update?commit=true');
curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: text/xml'));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, '<delete><query>user:' . $username . '</query></delete>');
curl_setopt($curl, CURLOPT_TIMEOUT, 30);
$response = curl_exec($curl);
if ($response === false) {
$err = curl_error($curl);
$_SESSION['return'][] = array(
'type' => 'warning',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'Could not remove Solr index: ' . print_r($err, true)
);
}
curl_close($curl);
}
$stmt = $pdo->prepare("DELETE FROM `alias` WHERE `goto` = :username"); $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `goto` = :username");
$stmt->execute(array( $stmt->execute(array(
':username' => $username ':username' => $username
@@ -5548,7 +5537,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
)); ));
$stmt = $pdo->prepare("SELECT `address`, `goto` FROM `alias` $stmt = $pdo->prepare("SELECT `address`, `goto` FROM `alias`
WHERE `goto` REGEXP :username"); WHERE `goto` REGEXP :username");
$stmt->execute(array(':username' => '(^|,)'.$username.'($|,)')); $stmt->execute(array(':username' => '(^|,)'.preg_quote($username, '/').'($|,)'));
$GotoData = $stmt->fetchAll(PDO::FETCH_ASSOC); $GotoData = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($GotoData as $gotos) { foreach ($GotoData as $gotos) {
$goto_exploded = explode(',', $gotos['goto']); $goto_exploded = explode(',', $gotos['goto']);
+32 -35
View File
@@ -1,9 +1,10 @@
<?php <?php
function init_db_schema() { function init_db_schema()
{
try { try {
global $pdo; global $pdo;
$db_version = "29072024_1000"; $db_version = "20112024_1105";
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'"); $stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
@@ -111,6 +112,10 @@ function init_db_schema() {
"c_name" => "VARCHAR(255) NOT NULL", "c_name" => "VARCHAR(255) NOT NULL",
"c_password" => "VARCHAR(255) NOT NULL DEFAULT ''", "c_password" => "VARCHAR(255) NOT NULL DEFAULT ''",
"c_cn" => "VARCHAR(255)", "c_cn" => "VARCHAR(255)",
"c_l" => "VARCHAR(255)",
"c_o" => "VARCHAR(255)",
"c_ou" => "VARCHAR(255)",
"c_telephonenumber" => "VARCHAR(255)",
"mail" => "VARCHAR(255) NOT NULL", "mail" => "VARCHAR(255) NOT NULL",
// TODO -> use TEXT and check if SOGo login breaks on empty aliases // TODO -> use TEXT and check if SOGo login breaks on empty aliases
"aliases" => "TEXT NOT NULL", "aliases" => "TEXT NOT NULL",
@@ -484,7 +489,7 @@ function init_db_schema() {
"quarantine_category" => "TINYINT(1) NOT NULL DEFAULT '1'", "quarantine_category" => "TINYINT(1) NOT NULL DEFAULT '1'",
"app_passwds" => "TINYINT(1) NOT NULL DEFAULT '1'", "app_passwds" => "TINYINT(1) NOT NULL DEFAULT '1'",
"pw_reset" => "TINYINT(1) NOT NULL DEFAULT '1'", "pw_reset" => "TINYINT(1) NOT NULL DEFAULT '1'",
), ),
"keys" => array( "keys" => array(
"primary" => array( "primary" => array(
"" => array("username") "" => array("username")
@@ -523,6 +528,7 @@ function init_db_schema() {
"cols" => array( "cols" => array(
"address" => "VARCHAR(255) NOT NULL", "address" => "VARCHAR(255) NOT NULL",
"goto" => "TEXT NOT NULL", "goto" => "TEXT NOT NULL",
"description" => "TEXT NOT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)", "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP", "modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"validity" => "INT(11)" "validity" => "INT(11)"
@@ -674,7 +680,7 @@ function init_db_schema() {
"mailbox_relayhost" => "TINYINT(1) NOT NULL DEFAULT '1'", "mailbox_relayhost" => "TINYINT(1) NOT NULL DEFAULT '1'",
"domain_relayhost" => "TINYINT(1) NOT NULL DEFAULT '1'", "domain_relayhost" => "TINYINT(1) NOT NULL DEFAULT '1'",
"domain_desc" => "TINYINT(1) NOT NULL DEFAULT '0'" "domain_desc" => "TINYINT(1) NOT NULL DEFAULT '0'"
), ),
"keys" => array( "keys" => array(
"primary" => array( "primary" => array(
"" => array("username") "" => array("username")
@@ -1147,7 +1153,7 @@ function init_db_schema() {
while ($row = array_shift($rows)) { while ($row = array_shift($rows)) {
$pdo->query($row['FKEY_DROP']); $pdo->query($row['FKEY_DROP']);
} }
foreach($properties['cols'] as $column => $type) { foreach ($properties['cols'] as $column => $type) {
$stmt = $pdo->query("SHOW COLUMNS FROM `" . $table . "` LIKE '" . $column . "'"); $stmt = $pdo->query("SHOW COLUMNS FROM `" . $table . "` LIKE '" . $column . "'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) { if ($num_results == 0) {
@@ -1161,12 +1167,11 @@ function init_db_schema() {
} }
} }
$pdo->query("ALTER TABLE `" . $table . "` ADD `" . $column . "` " . $type); $pdo->query("ALTER TABLE `" . $table . "` ADD `" . $column . "` " . $type);
} } else {
else {
$pdo->query("ALTER TABLE `" . $table . "` MODIFY COLUMN `" . $column . "` " . $type); $pdo->query("ALTER TABLE `" . $table . "` MODIFY COLUMN `" . $column . "` " . $type);
} }
} }
foreach($properties['keys'] as $key_type => $key_content) { foreach ($properties['keys'] as $key_type => $key_content) {
if (strtolower($key_type) == 'primary') { if (strtolower($key_type) == 'primary') {
foreach ($key_content as $key_values) { foreach ($key_content as $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`"; $fields = "`" . implode("`, `", $key_values) . "`";
@@ -1223,18 +1228,18 @@ function init_db_schema() {
$keys_to_exist = array(); $keys_to_exist = array();
if (isset($properties['keys']['unique']) && is_array($properties['keys']['unique'])) { if (isset($properties['keys']['unique']) && is_array($properties['keys']['unique'])) {
foreach ($properties['keys']['unique'] as $key_name => $key_values) { foreach ($properties['keys']['unique'] as $key_name => $key_values) {
$keys_to_exist[] = $key_name; $keys_to_exist[] = $key_name;
} }
} }
if (isset($properties['keys']['key']) && is_array($properties['keys']['key'])) { if (isset($properties['keys']['key']) && is_array($properties['keys']['key'])) {
foreach ($properties['keys']['key'] as $key_name => $key_values) { foreach ($properties['keys']['key'] as $key_name => $key_values) {
$keys_to_exist[] = $key_name; $keys_to_exist[] = $key_name;
} }
} }
// Index for foreign key must exist // Index for foreign key must exist
if (isset($properties['keys']['fkey']) && is_array($properties['keys']['fkey'])) { if (isset($properties['keys']['fkey']) && is_array($properties['keys']['fkey'])) {
foreach ($properties['keys']['fkey'] as $key_name => $key_values) { foreach ($properties['keys']['fkey'] as $key_name => $key_values) {
$keys_to_exist[] = $key_name; $keys_to_exist[] = $key_name;
} }
} }
// Step 2: Drop all vanished indexes // Step 2: Drop all vanished indexes
@@ -1251,33 +1256,29 @@ function init_db_schema() {
$pdo->query("ALTER TABLE `" . $table . "` DROP PRIMARY KEY"); $pdo->query("ALTER TABLE `" . $table . "` DROP PRIMARY KEY");
} }
} }
} } else {
else {
// Create table if it is missing // Create table if it is missing
$sql = "CREATE TABLE IF NOT EXISTS `" . $table . "` ("; $sql = "CREATE TABLE IF NOT EXISTS `" . $table . "` (";
foreach($properties['cols'] as $column => $type) { foreach ($properties['cols'] as $column => $type) {
$sql .= "`" . $column . "` " . $type . ","; $sql .= "`" . $column . "` " . $type . ",";
} }
foreach($properties['keys'] as $key_type => $key_content) { foreach ($properties['keys'] as $key_type => $key_content) {
if (strtolower($key_type) == 'primary') { if (strtolower($key_type) == 'primary') {
foreach ($key_content as $key_values) { foreach ($key_content as $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`"; $fields = "`" . implode("`, `", $key_values) . "`";
$sql .= "PRIMARY KEY (" . $fields . ")" . ","; $sql .= "PRIMARY KEY (" . $fields . ")" . ",";
} }
} } elseif (strtolower($key_type) == 'key') {
elseif (strtolower($key_type) == 'key') {
foreach ($key_content as $key_name => $key_values) { foreach ($key_content as $key_name => $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`"; $fields = "`" . implode("`, `", $key_values) . "`";
$sql .= "KEY `" . $key_name . "` (" . $fields . ")" . ","; $sql .= "KEY `" . $key_name . "` (" . $fields . ")" . ",";
} }
} } elseif (strtolower($key_type) == 'unique') {
elseif (strtolower($key_type) == 'unique') {
foreach ($key_content as $key_name => $key_values) { foreach ($key_content as $key_name => $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`"; $fields = "`" . implode("`, `", $key_values) . "`";
$sql .= "UNIQUE KEY `" . $key_name . "` (" . $fields . ")" . ","; $sql .= "UNIQUE KEY `" . $key_name . "` (" . $fields . ")" . ",";
} }
} } elseif (strtolower($key_type) == 'fkey') {
elseif (strtolower($key_type) == 'fkey') {
foreach ($key_content as $key_name => $key_values) { foreach ($key_content as $key_name => $key_values) {
@list($table_ref, $field_ref) = explode('.', $key_values['ref']); @list($table_ref, $field_ref) = explode('.', $key_values['ref']);
$sql .= "FOREIGN KEY `" . $key_name . "` (" . $key_values['col'] . ") REFERENCES `" . $table_ref . "` (`" . $field_ref . "`) $sql .= "FOREIGN KEY `" . $key_name . "` (" . $key_values['col'] . ") REFERENCES `" . $table_ref . "` (`" . $field_ref . "`)
@@ -1291,7 +1292,6 @@ function init_db_schema() {
} }
// Reset table attributes // Reset table attributes
$pdo->query("ALTER TABLE `" . $table . "` " . $properties['attr'] . ";"); $pdo->query("ALTER TABLE `" . $table . "` " . $properties['attr'] . ";");
} }
// Recreate SQL views // Recreate SQL views
@@ -1318,12 +1318,12 @@ function init_db_schema() {
$stmt = $pdo->query("SELECT NULL FROM `admin`"); $stmt = $pdo->query("SELECT NULL FROM `admin`");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) { if ($num_results == 0) {
$pdo->query("INSERT INTO `admin` (`username`, `password`, `superadmin`, `created`, `modified`, `active`) $pdo->query("INSERT INTO `admin` (`username`, `password`, `superadmin`, `created`, `modified`, `active`)
VALUES ('admin', '{SSHA256}K8eVJ6YsZbQCfuJvSUbaQRLr0HPLz5rC9IAp0PAFl0tmNDBkMDc0NDAyOTAxN2Rk', 1, NOW(), NOW(), 1)"); VALUES ('admin', '{SSHA256}K8eVJ6YsZbQCfuJvSUbaQRLr0HPLz5rC9IAp0PAFl0tmNDBkMDc0NDAyOTAxN2Rk', 1, NOW(), NOW(), 1)");
$pdo->query("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`) $pdo->query("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`)
SELECT `username`, 'ALL', NOW(), 1 FROM `admin` SELECT `username`, 'ALL', NOW(), 1 FROM `admin`
WHERE superadmin='1' AND `username` NOT IN (SELECT `username` FROM `domain_admins`);"); WHERE superadmin='1' AND `username` NOT IN (SELECT `username` FROM `domain_admins`);");
$pdo->query("DELETE FROM `admin` WHERE `username` NOT IN (SELECT `username` FROM `domain_admins`);"); $pdo->query("DELETE FROM `admin` WHERE `username` NOT IN (SELECT `username` FROM `domain_admins`);");
} }
// Insert new DB schema version // Insert new DB schema version
$pdo->query("REPLACE INTO `versions` (`application`, `version`) VALUES ('db_schema', '" . $db_version . "');"); $pdo->query("REPLACE INTO `versions` (`application`, `version`) VALUES ('db_schema', '" . $db_version . "');");
@@ -1351,7 +1351,7 @@ function init_db_schema() {
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.mailbox_format', \"maildir:\") WHERE JSON_VALUE(`attributes`, '$.mailbox_format') IS NULL;"); $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.mailbox_format', \"maildir:\") WHERE JSON_VALUE(`attributes`, '$.mailbox_format') IS NULL;");
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.quarantine_notification', \"never\") WHERE JSON_VALUE(`attributes`, '$.quarantine_notification') IS NULL;"); $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.quarantine_notification', \"never\") WHERE JSON_VALUE(`attributes`, '$.quarantine_notification') IS NULL;");
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.quarantine_category', \"reject\") WHERE JSON_VALUE(`attributes`, '$.quarantine_category') IS NULL;"); $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.quarantine_category', \"reject\") WHERE JSON_VALUE(`attributes`, '$.quarantine_category') IS NULL;");
foreach($tls_options as $tls_user => $tls_options) { foreach ($tls_options as $tls_user => $tls_options) {
$stmt = $pdo->prepare("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.tls_enforce_in', :tls_enforce_in), $stmt = $pdo->prepare("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.tls_enforce_in', :tls_enforce_in),
`attributes` = JSON_SET(`attributes`, '$.tls_enforce_out', :tls_enforce_out) `attributes` = JSON_SET(`attributes`, '$.tls_enforce_out', :tls_enforce_out)
WHERE `username` = :username"); WHERE `username` = :username");
@@ -1430,7 +1430,7 @@ function init_db_schema() {
":template" => $default_domain_template["template"] ":template" => $default_domain_template["template"]
)); ));
$row = $stmt->fetch(PDO::FETCH_ASSOC); $row = $stmt->fetch(PDO::FETCH_ASSOC);
if (empty($row)){ if (empty($row)) {
$stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`) $stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
VALUES (:type, :template, :attributes)"); VALUES (:type, :template, :attributes)");
$stmt->execute(array( $stmt->execute(array(
@@ -1445,7 +1445,7 @@ function init_db_schema() {
":template" => $default_mailbox_template["template"] ":template" => $default_mailbox_template["template"]
)); ));
$row = $stmt->fetch(PDO::FETCH_ASSOC); $row = $stmt->fetch(PDO::FETCH_ASSOC);
if (empty($row)){ if (empty($row)) {
$stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`) $stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
VALUES (:type, :template, :attributes)"); VALUES (:type, :template, :attributes)");
$stmt->execute(array( $stmt->execute(array(
@@ -1464,8 +1464,7 @@ function init_db_schema() {
'msg' => 'db_init_complete' 'msg' => 'db_init_complete'
); );
} }
} } catch (PDOException $e) {
catch (PDOException $e) {
if (php_sapi_name() == "cli") { if (php_sapi_name() == "cli") {
echo "DB initialization failed: " . print_r($e, true) . PHP_EOL; echo "DB initialization failed: " . print_r($e, true) . PHP_EOL;
} else { } else {
@@ -1504,8 +1503,7 @@ if (php_sapi_name() == "cli") {
SELECT `c_uid`, `domain`, `c_name`, `c_password`, `c_cn`, `mail`, `aliases`, `ad_aliases`, `ext_acl`, `kind`, `multiple_bookings` from sogo_view"); SELECT `c_uid`, `domain`, `c_name`, `c_password`, `c_cn`, `mail`, `aliases`, `ad_aliases`, `ext_acl`, `kind`, `multiple_bookings` from sogo_view");
$stmt = $pdo->query("DELETE FROM _sogo_static_view WHERE `c_uid` NOT IN (SELECT `username` FROM `mailbox` WHERE `active` = '1');"); $stmt = $pdo->query("DELETE FROM _sogo_static_view WHERE `c_uid` NOT IN (SELECT `username` FROM `mailbox` WHERE `active` = '1');");
echo "Fixed _sogo_static_view" . PHP_EOL; echo "Fixed _sogo_static_view" . PHP_EOL;
} } catch (Exception $e) {
catch ( Exception $e ) {
// Dunno // Dunno
} }
} }
@@ -1513,9 +1511,8 @@ if (php_sapi_name() == "cli") {
$m = new Memcached(); $m = new Memcached();
$m->addServer('memcached', 11211); $m->addServer('memcached', 11211);
$m->flush(); $m->flush();
echo "Cleaned up memcached". PHP_EOL; echo "Cleaned up memcached" . PHP_EOL;
} } catch (Exception $e) {
catch ( Exception $e ) {
// Dunno // Dunno
} }
init_db_schema(); init_db_schema();
+1
View File
@@ -68,6 +68,7 @@ try {
else { else {
$redis->connect('redis-mailcow', 6379); $redis->connect('redis-mailcow', 6379);
} }
$redis->auth(getenv("REDISPASS"));
} }
catch (Exception $e) { catch (Exception $e) {
// Stop when redis is not available // Stop when redis is not available
+11 -3
View File
@@ -4,6 +4,7 @@ if (!empty($_GET['sso_token'])) {
$username = domain_admin_sso('check', $_GET['sso_token']); $username = domain_admin_sso('check', $_GET['sso_token']);
if ($username !== false) { if ($username !== false) {
session_regenerate_id(true);
$_SESSION['mailcow_cc_username'] = $username; $_SESSION['mailcow_cc_username'] = $username;
$_SESSION['mailcow_cc_role'] = 'domainadmin'; $_SESSION['mailcow_cc_role'] = 'domainadmin';
header('Location: /mailbox'); header('Location: /mailbox');
@@ -87,18 +88,21 @@ if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
$as = check_login($login_user, $_POST["pass_user"]); $as = check_login($login_user, $_POST["pass_user"]);
if ($as == "admin") { if ($as == "admin") {
session_regenerate_id(true);
$_SESSION['mailcow_cc_username'] = $login_user; $_SESSION['mailcow_cc_username'] = $login_user;
$_SESSION['mailcow_cc_role'] = "admin"; $_SESSION['mailcow_cc_role'] = "admin";
header("Location: /debug"); header("Location: /debug");
die(); die();
} }
elseif ($as == "domainadmin") { elseif ($as == "domainadmin") {
session_regenerate_id(true);
$_SESSION['mailcow_cc_username'] = $login_user; $_SESSION['mailcow_cc_username'] = $login_user;
$_SESSION['mailcow_cc_role'] = "domainadmin"; $_SESSION['mailcow_cc_role'] = "domainadmin";
header("Location: /mailbox"); header("Location: /mailbox");
die(); die();
} }
elseif ($as == "user") { elseif ($as == "user") {
session_regenerate_id(true);
$_SESSION['mailcow_cc_username'] = $login_user; $_SESSION['mailcow_cc_username'] = $login_user;
$_SESSION['mailcow_cc_role'] = "user"; $_SESSION['mailcow_cc_role'] = "user";
$http_parameters = explode('&', $_SESSION['index_query_string']); $http_parameters = explode('&', $_SESSION['index_query_string']);
@@ -111,8 +115,10 @@ if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
header("Location: /mobileconfig.php"); header("Location: /mobileconfig.php");
die(); die();
} }
header("Location: /user"); if (!isset($_SESSION['oauth2_request'])) {
die(); header("Location: /user");
die();
}
} }
elseif ($as != "pending") { elseif ($as != "pending") {
unset($_SESSION['pending_mailcow_cc_username']); unset($_SESSION['pending_mailcow_cc_username']);
@@ -120,7 +126,9 @@ if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
unset($_SESSION['pending_tfa_methods']); unset($_SESSION['pending_tfa_methods']);
unset($_SESSION['mailcow_cc_username']); unset($_SESSION['mailcow_cc_username']);
unset($_SESSION['mailcow_cc_role']); unset($_SESSION['mailcow_cc_role']);
} } else {
session_regenerate_id(true);
}
} }
if (isset($_SESSION['mailcow_cc_role']) && (isset($_SESSION['acl']['login_as']) && $_SESSION['acl']['login_as'] == "1")) { if (isset($_SESSION['mailcow_cc_role']) && (isset($_SESSION['acl']['login_as']) && $_SESSION['acl']['login_as'] == "1")) {
+1
View File
@@ -93,6 +93,7 @@ $AVAILABLE_LANGUAGES = array(
'gr-gr' => 'Ελληνικά (Greek)', 'gr-gr' => 'Ελληνικά (Greek)',
'hu-hu' => 'Magyar (Hungarian)', 'hu-hu' => 'Magyar (Hungarian)',
'it-it' => 'Italiano (Italian)', 'it-it' => 'Italiano (Italian)',
'ja-jp' => '日本語 (Japanese)',
'ko-kr' => '한국어 (Korean)', 'ko-kr' => '한국어 (Korean)',
'lv-lv' => 'latviešu (Latvian)', 'lv-lv' => 'latviešu (Latvian)',
'lt-lt' => 'Lietuvių (Lithuanian)', 'lt-lt' => 'Lietuvių (Lithuanian)',
+14 -30
View File
@@ -179,9 +179,8 @@ $(document).ready(function() {
// Get script_data textarea content from form the button was clicked in // Get script_data textarea content from form the button was clicked in
var script = $('textarea[name="script_data"]', $(this).parents('form:first')).val(); var script = $('textarea[name="script_data"]', $(this).parents('form:first')).val();
$.ajax({ $.ajax({
dataType: 'json',
url: "/inc/ajax/sieve_validation.php", url: "/inc/ajax/sieve_validation.php",
type: "get", type: "post",
data: { script: script }, data: { script: script },
complete: function(data) { complete: function(data) {
var response = (data.responseText); var response = (data.responseText);
@@ -693,8 +692,8 @@ jQuery(function($){
} else if (item.attributes.rl_frame === "d"){ } else if (item.attributes.rl_frame === "d"){
item.attributes.rl_frame = lang_rl.day; item.attributes.rl_frame = lang_rl.day;
} }
item.attributes.rl_value = escapeHtml(item.attributes.rl_value); item.attributes.rl_value = (!item.attributes.rl_value) ? "∞" : escapeHtml(item.attributes.rl_value);
item.attributes.ratelimit = item.attributes.rl_value + " " + item.attributes.rl_frame;
if (item.template.toLowerCase() == "default"){ if (item.template.toLowerCase() == "default"){
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
@@ -818,14 +817,8 @@ jQuery(function($){
} }
}, },
{ {
title: 'rl_frame', title: lang_edit.ratelimit,
data: 'attributes.rl_frame', data: 'attributes.ratelimit',
defaultContent: '',
class: 'none',
},
{
title: 'rl_value',
data: 'attributes.rl_value',
defaultContent: '', defaultContent: '',
class: 'none', class: 'none',
}, },
@@ -894,7 +887,10 @@ jQuery(function($){
item.quota.value = humanFileSize(item.quota_used) + "/" + item.quota.value; item.quota.value = humanFileSize(item.quota_used) + "/" + item.quota.value;
item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox); item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox);
item.last_mail_login = item.last_imap_login + '/' + item.last_pop3_login + '/' + item.last_smtp_login + '/' + item.last_sso_login; item.last_mail_login = (item.attributes.imap_access == 1 ? '<div class="text-start badge bg-info mb-2" style="min-width: 70px;">IMAP @ ' + unix_time_format(Number(item.last_imap_login)) + '</div><br>' : '') +
(item.attributes.pop3_access == 1 ? '<div class="text-start badge bg-info mb-2" style="min-width: 70px;">POP3 @ ' + unix_time_format(Number(item.last_pop3_login)) + '</div><br>' : '') +
(item.attributes.smtp_access == 1 ? '<div class="text-start badge bg-info mb-2" style="min-width: 70px;">SMTP @ ' + unix_time_format(Number(item.last_smtp_login)) + '</div><br>' : '') +
'<div class="text-start badge bg-info" style="min-width: 70px;">SSO @ ' + unix_time_format(Number(item.last_sso_login)) + '</div>';
/* /*
if (!item.rl) { if (!item.rl) {
item.rl = '∞'; item.rl = '∞';
@@ -1010,14 +1006,7 @@ jQuery(function($){
data: 'last_mail_login', data: 'last_mail_login',
searchable: false, searchable: false,
defaultContent: '', defaultContent: '',
responsivePriority: 7, responsivePriority: 7
render: function (data, type) {
res = data.split("/");
return '<div class="text-start badge bg-info mb-2" style="min-width: 70px;">IMAP @ ' + unix_time_format(Number(res[0])) + '</div><br>' +
'<div class="text-start badge bg-info mb-2" style="min-width: 70px;">POP3 @ ' + unix_time_format(Number(res[1])) + '</div><br>' +
'<div class="text-start badge bg-info mb-2" style="min-width: 70px;">SMTP @ ' + unix_time_format(Number(res[2])) + '</div><br>' +
'<div class="text-start badge bg-info" style="min-width: 70px;">SSO @ ' + unix_time_format(Number(res[3])) + '</div>';
}
}, },
{ {
title: lang.last_pw_change, title: lang.last_pw_change,
@@ -1183,7 +1172,8 @@ jQuery(function($){
} else if (item.attributes.rl_frame === "d"){ } else if (item.attributes.rl_frame === "d"){
item.attributes.rl_frame = lang_rl.day; item.attributes.rl_frame = lang_rl.day;
} }
item.attributes.rl_value = escapeHtml(item.attributes.rl_value); item.attributes.rl_value = (!item.attributes.rl_value) ? "∞" : escapeHtml(item.attributes.rl_value);
item.attributes.ratelimit = item.attributes.rl_value + " " + item.attributes.rl_frame;
item.attributes.quota = humanFileSize(item.attributes.quota); item.attributes.quota = humanFileSize(item.attributes.quota);
@@ -1328,14 +1318,8 @@ jQuery(function($){
} }
}, },
{ {
title: "rl_frame", title: lang_edit.ratelimit,
data: 'attributes.rl_frame', data: 'attributes.ratelimit',
defaultContent: '',
class: 'none',
},
{
title: 'rl_value',
data: 'attributes.rl_value',
defaultContent: '', defaultContent: '',
class: 'none', class: 'none',
}, },
+8
View File
@@ -202,6 +202,14 @@ jQuery(function($){
data: 'address', data: 'address',
defaultContent: '' defaultContent: ''
}, },
{
title: lang.description,
data: 'description',
defaultContent: '',
render: function (data, type) {
return escapeHtml(data);
}
},
{ {
title: lang.alias_valid_until, title: lang.alias_valid_until,
data: 'validity', data: 'validity',
+2 -32
View File
@@ -510,16 +510,6 @@ if (isset($_GET['query'])) {
$_SESSION['challenge'] = $WebAuthn->getChallenge(); $_SESSION['challenge'] = $WebAuthn->getChallenge();
return; return;
break; break;
case "fail2ban":
if (!isset($_SESSION['mailcow_cc_role'])){
switch ($object) {
case 'banlist':
header('Content-Type: text/plain');
echo fail2ban('banlist', 'get', $extra);
break;
}
}
break;
} }
if (isset($_SESSION['mailcow_cc_role'])) { if (isset($_SESSION['mailcow_cc_role'])) {
switch ($category) { switch ($category) {
@@ -1077,9 +1067,10 @@ if (isset($_GET['query'])) {
['db' => 'last_mail_login', 'dt' => 4, 'dummy' => true, 'order_subquery' => "SELECT MAX(`datetime`) FROM `sasl_log` WHERE `service` != 'SSO' AND `username` = `m`.`username`"], ['db' => 'last_mail_login', 'dt' => 4, 'dummy' => true, 'order_subquery' => "SELECT MAX(`datetime`) FROM `sasl_log` WHERE `service` != 'SSO' AND `username` = `m`.`username`"],
['db' => 'last_pw_change', 'dt' => 5, 'dummy' => true, 'order_subquery' => "JSON_EXTRACT(attributes, '$.passwd_update')"], ['db' => 'last_pw_change', 'dt' => 5, 'dummy' => true, 'order_subquery' => "JSON_EXTRACT(attributes, '$.passwd_update')"],
['db' => 'in_use', 'dt' => 6, 'dummy' => true, 'order_subquery' => "(SELECT SUM(bytes) FROM `quota2` WHERE `quota2`.`username` = `m`.`username`) / `m`.`quota`"], ['db' => 'in_use', 'dt' => 6, 'dummy' => true, 'order_subquery' => "(SELECT SUM(bytes) FROM `quota2` WHERE `quota2`.`username` = `m`.`username`) / `m`.`quota`"],
['db' => 'name', 'dt' => 7],
['db' => 'messages', 'dt' => 17, 'dummy' => true, 'order_subquery' => "SELECT SUM(messages) FROM `quota2` WHERE `quota2`.`username` = `m`.`username`"], ['db' => 'messages', 'dt' => 17, 'dummy' => true, 'order_subquery' => "SELECT SUM(messages) FROM `quota2` WHERE `quota2`.`username` = `m`.`username`"],
['db' => 'tags', 'dt' => 20, 'dummy' => true, 'search' => ['join' => 'LEFT JOIN `tags_mailbox` AS `tm` ON `tm`.`username` = `m`.`username`', 'where_column' => '`tm`.`tag_name`']], ['db' => 'tags', 'dt' => 20, 'dummy' => true, 'search' => ['join' => 'LEFT JOIN `tags_mailbox` AS `tm` ON `tm`.`username` = `m`.`username`', 'where_column' => '`tm`.`tag_name`']],
['db' => 'active', 'dt' => 21] ['db' => 'active', 'dt' => 21],
]; ];
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/lib/ssp.class.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/lib/ssp.class.php';
@@ -1420,10 +1411,6 @@ if (isset($_GET['query'])) {
break; break;
case "fail2ban": case "fail2ban":
switch ($object) { switch ($object) {
case 'banlist':
header('Content-Type: text/plain');
echo fail2ban('banlist', 'get', $extra);
break;
default: default:
$data = fail2ban('get'); $data = fail2ban('get');
process_get_return($data); process_get_return($data);
@@ -1641,23 +1628,6 @@ if (isset($_GET['query'])) {
); );
echo json_encode($temp, JSON_UNESCAPED_SLASHES); echo json_encode($temp, JSON_UNESCAPED_SLASHES);
break; break;
case "solr":
$solr_status = solr_status();
$solr_size = ($solr_status['status']['dovecot-fts']['index']['size']);
$solr_documents = ($solr_status['status']['dovecot-fts']['index']['numDocs']);
if (strtolower(getenv('SKIP_SOLR')) != 'n') {
$solr_enabled = false;
}
else {
$solr_enabled = true;
}
echo json_encode(array(
'type' => 'info',
'solr_enabled' => $solr_enabled,
'solr_size' => $solr_size,
'solr_documents' => $solr_documents
));
break;
case "host": case "host":
if (!$extra){ if (!$extra){
$stats = docker("host_stats"); $stats = docker("host_stats");
+1
View File
@@ -493,6 +493,7 @@
"client_configuration": "Guies de configuració per als clients de correu més habituals", "client_configuration": "Guies de configuració per als clients de correu més habituals",
"create_syncjob": "Afegir treball de sincronitzaió", "create_syncjob": "Afegir treball de sincronitzaió",
"day": "Dia", "day": "Dia",
"description": "Descripció",
"direct_aliases": "Adreces àlies directes", "direct_aliases": "Adreces àlies directes",
"direct_aliases_desc": "Els àlies directes sí que es veuen afectat per la configuració de l'usuari", "direct_aliases_desc": "Els àlies directes sí que es veuen afectat per la configuració de l'usuari",
"eas_reset": "Fer un reset de la cache d'ActiveSync del dispositiu", "eas_reset": "Fer un reset de la cache d'ActiveSync del dispositiu",
+2 -4
View File
@@ -521,7 +521,6 @@
"external_logs": "Externí logy", "external_logs": "Externí logy",
"history_all_servers": "Záznam (všechny servery)", "history_all_servers": "Záznam (všechny servery)",
"in_memory_logs": "Logy v paměti", "in_memory_logs": "Logy v paměti",
"jvm_memory_solr": "Spotřeba paměti JVM",
"last_modified": "Naposledy změněn", "last_modified": "Naposledy změněn",
"log_info": "<p><b>Logy v paměti</b> jsou shromažďovány v Redis seznamech a jsou oříznuty na LOG_LINES (%d) každou minutu, aby se nepřetěžoval server.\r\n <br>Logy v paměti nemají být trvalé. Všechny aplikace, které logují do paměti, zároveň logují i do Docker služby podle nastavení logging driveru.\r\n <br>Logy v paměti lze použít pro ladění drobných problémů s kontejnery.</p>\r\n <p><b>Externí logy</b> jsou shromažďovány pomocí API dané aplikace.</p>\r\n <p><b>Statické logy</b> jsou většinou logy činností, které nejsou zaznamenávány do Docker služby, ale přesto je dobré je schraňovat (výjimkou jsou logy API).</p>", "log_info": "<p><b>Logy v paměti</b> jsou shromažďovány v Redis seznamech a jsou oříznuty na LOG_LINES (%d) každou minutu, aby se nepřetěžoval server.\r\n <br>Logy v paměti nemají být trvalé. Všechny aplikace, které logují do paměti, zároveň logují i do Docker služby podle nastavení logging driveru.\r\n <br>Logy v paměti lze použít pro ladění drobných problémů s kontejnery.</p>\r\n <p><b>Externí logy</b> jsou shromažďovány pomocí API dané aplikace.</p>\r\n <p><b>Statické logy</b> jsou většinou logy činností, které nejsou zaznamenávány do Docker služby, ale přesto je dobré je schraňovat (výjimkou jsou logy API).</p>",
"login_time": "Čas", "login_time": "Čas",
@@ -530,8 +529,6 @@
"restart_container": "Restartovat", "restart_container": "Restartovat",
"service": "Služba", "service": "Služba",
"size": "Velikost", "size": "Velikost",
"solr_dead": "Solr se spouští, je vypnutý nebo spadl.",
"solr_status": "Stav Solr",
"started_at": "Spuštěn", "started_at": "Spuštěn",
"started_on": "Spuštěno", "started_on": "Spuštěno",
"static_logs": "Statické logy", "static_logs": "Statické logy",
@@ -872,7 +869,7 @@
"recipient_map": "Mapa příjemce", "recipient_map": "Mapa příjemce",
"recipient_map_info": "Mapy příjemců slouží k nahrazení cílové adresy zprávy před doručením.", "recipient_map_info": "Mapy příjemců slouží k nahrazení cílové adresy zprávy před doručením.",
"recipient_map_new": "Nový přijemce", "recipient_map_new": "Nový přijemce",
"recipient_map_new_info": "Cílová adresa mapy příjemce musí být platná emailová adresa.", "recipient_map_new_info": "Cílová adresa mapy příjemce musí být emailová adresa nebo název domény.",
"recipient_map_old": "Původní příjemce", "recipient_map_old": "Původní příjemce",
"recipient_map_old_info": "Původní příjemce musí být platná emailová adresa nebo název domény.", "recipient_map_old_info": "Původní příjemce musí být platná emailová adresa nebo název domény.",
"recipient_maps": "Mapy příjemců", "recipient_maps": "Mapy příjemců",
@@ -1164,6 +1161,7 @@
"created_on": "Vytvoreno", "created_on": "Vytvoreno",
"daily": "Každý den", "daily": "Každý den",
"day": "den", "day": "den",
"description": "Popis",
"delete_ays": "Potvrďte odstranění.", "delete_ays": "Potvrďte odstranění.",
"direct_aliases": "Přímé aliasy", "direct_aliases": "Přímé aliasy",
"direct_aliases_desc": "Na přímé aliasy se uplatňuje filtr spamu a nastavení pravidel TLS", "direct_aliases_desc": "Na přímé aliasy se uplatňuje filtr spamu a nastavení pravidel TLS",

Some files were not shown because too many files have changed in this diff Show More