1
0
mirror of https://github.com/mail-in-a-box/mailinabox.git synced 2024-12-24 07:37:04 +00:00

Merge remote-tracking branch 'origin/20.04'

This commit is contained in:
github@kiekerjan.isdronken.nl 2021-04-30 23:32:01 +02:00
commit a7955b39dd
55 changed files with 1432 additions and 139 deletions

View File

@ -1,8 +1,8 @@
CHANGELOG
=========
In Development
--------------
v0.53 (April 12, 2021)
----------------------
Software updates:

View File

@ -1,3 +1,12 @@
This is not the original Mail-in-a-Box. See https://github.com/mail-in-a-box/mailinabox for the real deal! I made a number of modifications to to:
- add geoipblocking on the admin web console
- add geoipblocking for ssh access
- make fail2ban a more stricter
- add fail2ban filter for web scanners
- other small stuff
Original mailinabox content starts here:
Mail-in-a-Box
=============
@ -23,7 +32,7 @@ Additionally, this project has a [Code of Conduct](CODE_OF_CONDUCT.md), which su
In The Box
----------
Mail-in-a-Box turns a fresh Ubuntu 18.04 LTS 64-bit machine into a working mail server by installing and configuring various components.
Mail-in-a-Box turns a fresh Ubuntu 20.04 or 18.04 LTS 64-bit machine into a working mail server by installing and configuring various components.
It is a one-click email appliance. There are no user-configurable setup options. It "just works."
@ -58,7 +67,7 @@ Clone this repository and checkout the tag corresponding to the most recent rele
$ git clone https://github.com/mail-in-a-box/mailinabox
$ cd mailinabox
$ git checkout v0.52
$ git checkout v0.53
Begin the installation.

View File

@ -0,0 +1,5 @@
#!/bin/bash
#
doveadm expunge -A mailbox Trash savedbefore 120d
doveadm expunge -A mailbox Spam savedbefore 120d

2
conf/cron/miab_dovecot Normal file
View File

@ -0,0 +1,2 @@
#!/bin/bash
/usr/bin/doveadm fts rescan -A > /dev/null 2>&1

2
conf/cron/miab_solr Normal file
View File

@ -0,0 +1,2 @@
1 */1 * * * root /usr/bin/curl -s http://127.0.0.1:8983/solr/update?commit=true >/dev/null 2>&1
30 3 * * * root /usr/bin/curl -s http://127.0.0.1:8983/solr/update?optimize=true >/dev/null 2>&1

View File

@ -0,0 +1,24 @@
# Fail2Ban configuration file
#
# Regexp to catch known spambots and software alike. Please verify
# that it is your intent to block IPs which were driven by
# above mentioned bots.
[Definition]
badbotscustom = EmailCollector|WebEMailExtrac|TrackBack/1\.02|sogou music spider|(?:Mozilla/\d+\.\d+ )?Jorgee
badbots = Atomic_Email_Hunter/4\.0|atSpider/1\.0|autoemailspider|bwh3_user_agent|China Local Browse 2\.6|ContactBot/0\.2|ContentSmartz|DataCha0s/2\.0|DBrowse 1\.4b|DBrowse 1\.4d|Demo Bot DOT 16b|Demo Bot Z 16b|DSurf15a 01|DSurf15a 71|DSurf15a 81|DSurf15a VA|EBrowse 1\.4b|Educate Search VxB|EmailSiphon|EmailSpider|EmailWolf 1\.00|ESurf15a 15|ExtractorPro|Franklin Locator 1\.8|FSurf15a 01|Full Web Bot 0416B|Full Web Bot 0516B|Full Web Bot 2816B|Guestbook Auto Submitter|Industry Program 1\.0\.x|ISC Systems iRc Search 2\.1|IUPUI Research Bot v 1\.9a|LARBIN-EXPERIMENTAL \(efp@gmx\.net\)|LetsCrawl\.com/1\.0 \+http\://letscrawl\.com/|Lincoln State Web Browser|LMQueueBot/0\.2|LWP\:\:Simple/5\.803|Mac Finder 1\.0\.xx|MFC Foundation Class Library 4\.0|Microsoft URL Control - 6\.00\.8xxx|Missauga Locate 1\.0\.0|Missigua Locator 1\.9|Missouri College Browse|Mizzu Labs 2\.2|Mo College 1\.9|MVAClient|Mozilla/2\.0 \(compatible; NEWT ActiveX; Win32\)|Mozilla/3\.0 \(compatible; Indy Library\)|Mozilla/3\.0 \(compatible; scan4mail \(advanced version\) http\://www\.peterspages\.net/?scan4mail\)|Mozilla/4\.0 \(compatible; Advanced Email Extractor v2\.xx\)|Mozilla/4\.0 \(compatible; Iplexx Spider/1\.0 http\://www\.iplexx\.at\)|Mozilla/4\.0 \(compatible; MSIE 5\.0; Windows NT; DigExt; DTS Agent|Mozilla/4\.0 efp@gmx\.net|Mozilla/5\.0 \(Version\: xxxx Type\:xx\)|NameOfAgent \(CMS Spider\)|NASA Search 1\.0|Nsauditor/1\.x|PBrowse 1\.4b|PEval 1\.4b|Poirot|Port Huron Labs|Production Bot 0116B|Production Bot 2016B|Production Bot DOT 3016B|Program Shareware 1\.0\.2|PSurf15a 11|PSurf15a 51|PSurf15a VA|psycheclone|RSurf15a 41|RSurf15a 51|RSurf15a 81|searchbot admin@google\.com|ShablastBot 1\.0|snap\.com beta crawler v0|Snapbot/1\.0|Snapbot/1\.0 \(Snap Shots, \+http\://www\.snap\.com\)|sogou develop spider|Sogou Orion spider/3\.0\(\+http\://www\.sogou\.com/docs/help/webmasters\.htm#07\)|sogou spider|Sogou web spider/3\.0\(\+http\://www\.sogou\.com/docs/help/webmasters\.htm#07\)|sohu agent|SSurf15a 11 |TSurf15a 11|Under the Rainbow 2\.2|User-Agent\: Mozilla/4\.0 \(compatible; MSIE 6\.0; Windows NT 5\.1\)|VadixBot|WebVulnCrawl\.unknown/1\.0 libwww-perl/5\.803|Wells Search II|WEP Search 00
failregex = ^<HOST> -.*"(GET|POST|HEAD).*HTTP.*"(?:%(badbots)s|%(badbotscustom)s)"$
ignoreregex =
datepattern = ^[^\[]*\[({DATE})
{^LN-BEG}
# DEV Notes:
# List of bad bots fetched from http://www.user-agents.org
# Generated on Thu Nov 7 14:23:35 PST 2013 by files/gen_badbots.
#
# Author: Yaroslav Halchenko

View File

@ -0,0 +1,12 @@
# Fail2Ban filter Mail-in-a-Box geo ip block
[INCLUDES]
before = common.conf
[Definition]
_daemon = mailinabox
failregex = .* - Geoip blocked <HOST>
ignoreregex =

View File

@ -0,0 +1,10 @@
# Fail2Ban filter sshd ip block according to https://www.axllent.org/docs/ssh-geoip/
[INCLUDES]
before = common.conf
[Definition]
failregex = .* DENY geoipblocked connection from <HOST>
ignoreregex =

View File

@ -0,0 +1,237 @@
# Fail2Ban Web Exploits Filter
# Author & Copyright: Mitchell Krog - mitchellkrog@gmail.com
# REPO: https://github.com/mitchellkrogza/Fail2Ban.WebExploits
# V0.1.27
# Last Updated: Tue May 8 11:08:42 SAST 2018
[Definition]
failregex = ^<HOST> -.*(GET|POST|HEAD).*(/\.git/config)
^<HOST> -.*(GET|POST).*/administrator/index\.php.*500
^<HOST> -.*(GET|POST|HEAD).*(/:8880/)
^<HOST> -.*(GET|POST|HEAD).*(/1\.sql)
^<HOST> -.*(GET|POST|HEAD).*(/addons/theme/stv1/_static/image/favicon\.ico)
^<HOST> -.*(GET|POST|HEAD).*(/addons/theme/stv1/_static/ts2/layout\.css)
^<HOST> -.*(GET|POST|HEAD).*(/addons/theme/stv2/_static/ts2/layout\.css)
^<HOST> -.*(GET|POST|HEAD).*(/Admin/Common/HelpLinks\.xml)
^<HOST> -.*(GET|POST|HEAD).*(/admin-console)
^<HOST> -.*(GET|POST|HEAD).*(/admin/inc/xml\.xslt)
^<HOST> -.*(GET|POST|HEAD).*(/administrator/components/com_xcloner-backupandrestore/index2\.php)
# ^<HOST> -.*(GET|POST|HEAD).*(/administrator/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/administrator/manifests/files/joomla\.xml)
^<HOST> -.*(GET|POST|HEAD).*(/admin/mysql2/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/admin/mysql/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/admin/phpMyAdmin/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/admin/pma/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/admin/PMA/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/admin/SouthidcEditor/ButtonImage/standard/componentmenu\.gif)
^<HOST> -.*(GET|POST|HEAD).*(/admin/SouthidcEditor/Dialog/dialog\.js)
^<HOST> -.*(GET|POST|HEAD).*(/admin/SouthidcEditor/ewebeditor\.asp)
^<HOST> -.*(GET|POST|HEAD).*(/API/DW/Dwplugin/SystemLabel/SiteConfig\.htm)
^<HOST> -.*(GET|POST|HEAD).*(/API/DW/Dwplugin/TemplateManage/login_site\.htm)
^<HOST> -.*(GET|POST|HEAD).*(/API/DW/Dwplugin/TemplateManage/manage_site\.htm)
^<HOST> -.*(GET|POST|HEAD).*(/API/DW/Dwplugin/TemplateManage/save_template\.htm)
^<HOST> -.*(GET|POST|HEAD).*(/API/DW/Dwplugin/ThirdPartyTags/SiteFactory\.xml)
^<HOST> -.*(GET|POST|HEAD).*(/api/jsonws/invoke)
^<HOST> -.*(GET|POST|HEAD).*(/app/home/skins/default/style\.css)
^<HOST> -.*(GET|POST|HEAD).*(/app/js/source/wcmlib/WCMConstants\.js)
^<HOST> -.*(GET|POST|HEAD).*(/apple-app-site-association)
^<HOST> -.*(GET|POST|HEAD).*(/app/Tpl/fanwe_1/js/)
^<HOST> -.*(GET|POST|HEAD).*(/app/etc/local\.xml)
^<HOST> -.*(GET|POST|HEAD).*(/Autodiscover/Autodiscover\.xml)
^<HOST> -.*(GET|POST|HEAD).*(/_asterisk/)
^<HOST> -.*(GET|POST|HEAD).*(/backup\.sql)
^<HOST> -.*(GET|POST|HEAD).*(/bencandy\.php)
^<HOST> -.*(GET|POST|HEAD).*(/blog/administrator/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/boaform/admin/formLogin)
^<HOST> -.*(GET|POST|HEAD).*(/cardamom\.html)
^<HOST> -.*(GET|POST|HEAD).*(/cgi-bin/php)
^<HOST> -.*(GET|POST|HEAD).*(/cgi-bin/php5)
^<HOST> -.*(GET|POST|HEAD).*(/cgi/common\.cgi)
^<HOST> -.*(GET|POST|HEAD).*(/CGI/Execute)
^<HOST> -.*(GET|POST|HEAD).*(/check\.proxyradar\.com/azenv\.php)
^<HOST> -.*(GET|POST|HEAD).*(/ckeditor/ckfinder/ckfinder\.html)
^<HOST> -.*(GET|POST|HEAD).*(/ckeditor/ckfinder/install\.txt)
^<HOST> -.*(GET|POST|HEAD).*(/ckfinder/ckfinder\.html)
^<HOST> -.*(GET|POST|HEAD).*(/ckfinder/install\.txt)
^<HOST> -.*(GET|POST|HEAD).*(/ckupload\.php)
^<HOST> -.*(GET|POST|HEAD).*(/claroline/phpMyAdmin/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/clases\.gone\.php)
^<HOST> -.*(GET|POST|HEAD).*(/cms/administrator)
^<HOST> -.*(GET|POST|HEAD).*(/command\.php)
^<HOST> -.*(GET|POST|HEAD).*(/components/com_adsmanager/js/fullnoconflict\.js)
^<HOST> -.*(GET|POST|HEAD).*(/components/com_b2jcontact/css/b2jcontact\.css)
^<HOST> -.*(GET|POST|HEAD).*(/components/com_b2jcontact/router\.php)
^<HOST> -.*(GET|POST|HEAD).*(/components/com_foxcontact/js/jtext\.js)
^<HOST> -.*(GET|POST|HEAD).*(/components/com_sexycontactform/assets/js/index\.html)
^<HOST> -.*(GET|POST|HEAD).*(/console/)
^<HOST> -.*(GET|POST|HEAD).*(/console/auth/reg_newuser\.jsp)
^<HOST> -.*(GET|POST|HEAD).*(/console/include/not_login\.htm)
^<HOST> -.*(GET|POST|HEAD).*(/console/js/CTRSRequestParam\.js)
^<HOST> -.*(GET|POST|HEAD).*(/console/js/CWCMDialogHead\.js)
^<HOST> -.*(GET|POST|HEAD).*(/customer/account/login/referer/)
^<HOST> -.*(GET|POST|HEAD).*(/currentsetting\.htm)
^<HOST> -.*(GET|POST|HEAD).*(/CuteSoft_Client/CuteEditor/Help/default\.htm)
^<HOST> -.*(GET|POST|HEAD).*(/CuteSoft_Client/CuteEditor/ImageEditor/listfiles\.aspx)
^<HOST> -.*(GET|POST|HEAD).*(/CuteSoft_Client/CuteEditor/Images/log\.gif)
^<HOST> -.*(GET|POST|HEAD).*(/data/admin/ver\.txt)
^<HOST> -.*(GET|POST|HEAD).*(/database\.sql)
^<HOST> -.*(GET|POST|HEAD).*(/data\.sql)
^<HOST> -.*(GET|POST|HEAD).*(/datacenter/downloadApp/showDownload\.do)
^<HOST> -.*(GET|POST|HEAD).*(/db/)
^<HOST> -.*(GET|POST|HEAD).*(/dbadmin/)
^<HOST> -.*(GET|POST|HEAD).*(/dbadmin/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/db_backup\.sql)
^<HOST> -.*(GET|POST|HEAD).*(/dbdump\.sql)
^<HOST> -.*(GET|POST|HEAD).*(/db\.sql)
^<HOST> -.*(GET|POST|HEAD).*(/db/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/dump\.sql)
^<HOST> -.*(GET|POST|HEAD).*(/deptWebsiteAction\.do)
^<HOST> -.*(GET|POST|HEAD).*(/eams/static/scripts/grade/course/input\.js)
^<HOST> -.*(GET|POST|HEAD).*(/editor/js/fckeditorcode_ie\.js)
^<HOST> -.*(GET|POST|HEAD).*(\.env\.dev\.local)
^<HOST> -.*(GET|POST|HEAD).*(/\.env\.development\.local)
^<HOST> -.*(GET|POST|HEAD).*(/\.env\.prod\.local)
^<HOST> -.*(GET|POST|HEAD).*(/\.env\.production\.local)
^<HOST> -.*(GET|POST|HEAD).*(/examples/file-manager\.html)
^<HOST> -.*(GET|POST|HEAD).*(/getcfg\.php)
^<HOST> -.*(GET|POST|HEAD).*(/get_password\.php)
^<HOST> -.*(GET|POST|HEAD).*(/\.git/info/)
^<HOST> -.*(GET|POST|HEAD).*(/Hello\.World)
^<HOST> -.*(GET|POST|HEAD).*(/hndUnblock\.cgi)
^<HOST> -.*(GET|POST|HEAD).*(/images/login9/login_33\.jpg)
^<HOST> -.*(GET|POST|HEAD).*(/include/dialog/config\.php)
^<HOST> -.*(GET|POST|HEAD).*(/include/install_ocx\.aspx)
^<HOST> -.*(GET|POST|HEAD).*(/index\.action)
^<HOST> -.*(GET|POST|HEAD).*(/ip_js\.php)
^<HOST> -.*(GET|POST|HEAD).*(/issmall/)
^<HOST> -.*(GET|POST|HEAD).*(/jenkins/script)
^<HOST> -.*(GET|POST|HEAD).*(/jenkins/login)
^<HOST> -.*(GET|POST|HEAD).*(/jm-ajax/upload_file/)
^<HOST> -.*(GET|POST|HEAD).*(/jmx-console)
^<HOST> -.*(GET|POST|HEAD).*(/js/tools\.js)
^<HOST> -.*(GET|POST|HEAD).*(/letrokart.sql)
^<HOST> -.*(GET|POST|HEAD).*(/libraries/sfn\.php)
^<HOST> -.*(GET|POST|HEAD).*(/localhost\.sql)
^<HOST> -.*(GET|POST|HEAD).*(login\.destroy\.session)
^<HOST> -.*(GET|POST|HEAD).*(/login/Jeecms\.do)
^<HOST> -.*(GET|POST|HEAD).*(/logo_img\.php)
^<HOST> -.*(GET|POST|HEAD).*(/maintlogin\.jsp)
^<HOST> -.*(GET|POST|HEAD).*(/manager/html)
^<HOST> -.*(GET|POST|HEAD).*(/manager/status)
^<HOST> -.*(GET|POST|HEAD).*(/magmi/conf/magmi\.ini)
^<HOST> -.*(GET|POST|HEAD).*(/master/login\.aspx)
^<HOST> -.*(GET|POST|HEAD).*(/media/com_hikashop/js/hikashop\.js)
^<HOST> -.*(GET|POST|HEAD).*(/modules/attributewizardpro/config\.xml)
^<HOST> -.*(GET|POST|HEAD).*(/modules/columnadverts/config\.xml)
^<HOST> -.*(GET|POST|HEAD).*(/modules/fieldvmegamenu/config\.xml)
^<HOST> -.*(GET|POST|HEAD).*(/modules/homepageadvertise2/config\.xml)
^<HOST> -.*(GET|POST|HEAD).*(/modules/homepageadvertise/config\.xml)
^<HOST> -.*(GET|POST|HEAD).*(/modules/mod_simplefileuploadv1\.3/elements/udd\.php)
^<HOST> -.*(GET|POST|HEAD).*(/modules/pk_flexmenu/config\.xml)
^<HOST> -.*(GET|POST|HEAD).*(/modules/pk_vertflexmenu/config\.xml)
^<HOST> -.*(GET|POST|HEAD).*(/modules/wdoptionpanel/config\.xml)
^<HOST> -.*(GET|POST|HEAD).*(/msd)
^<HOST> -.*(GET|POST|HEAD).*(/msd1\.24\.4)
^<HOST> -.*(GET|POST|HEAD).*(/msd1\.24stable)
^<HOST> -.*(GET|POST|HEAD).*(mstshash=NCRACK_USER)
^<HOST> -.*(GET|POST|HEAD).*(/muieblackcat)
^<HOST> -.*(GET|POST|HEAD).*(/myadmin2/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/myadmin/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/myadmin/scripts/setup\.php)
^<HOST> -.*(GET|POST|HEAD).*(/MyAdmin/scripts/setup\.php)
^<HOST> -.*(GET|POST|HEAD).*(/mysql-admin/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/mysqladmin/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/mysqldumper)
^<HOST> -.*(GET|POST|HEAD).*(/mySqlDumper)
^<HOST> -.*(GET|POST|HEAD).*(/MySQLDumper)
^<HOST> -.*(GET|POST|HEAD).*(/mysqldump\.sql)
^<HOST> -.*(GET|POST|HEAD).*(/mysql\.sql)
^<HOST> -.*(GET|POST|HEAD).*(/phpadmin/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/phpma/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/phpMyadmin_bak/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/phpMyAdmin/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/phpMyAdmin/phpMyAdmin/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/phpMyAdmin/scripts/setup\.php)
^<HOST> -.*(GET|POST|HEAD).*(/plugins/anchor/anchor\.js)
^<HOST> -.*(GET|POST|HEAD).*(/plugins/filemanager/filemanager/js)
^<HOST> -.*(GET|POST|HEAD).*(/plus/download\.php)
^<HOST> -.*(GET|POST|HEAD).*(/plus/heightsearch\.php)
^<HOST> -.*(GET|POST|HEAD).*(/plus/rssmap\.html)
^<HOST> -.*(GET|POST|HEAD).*(/plus/sitemap\.html)
^<HOST> -.*(GET|POST|HEAD).*(/pma/)
^<HOST> -.*(GET|POST|HEAD).*(/PMA/)
^<HOST> -.*(GET|POST|HEAD).*(/PMA2/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/pma/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/PMA/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/pmamy2/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/pmamy/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/pma-old/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/pma/scripts/setup\.php)
^<HOST> -.*(GET|POST|HEAD).*(/pmd/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/privacy\.txt)
^<HOST> -.*(GET|POST|HEAD).*(/resources/style/images/login/btn\.png)
^<HOST> -.*(GET|POST|HEAD).*(/Scripts/jquery/maticsoft\.jquery\.min\.js)
^<HOST> -.*(GET|POST|HEAD).*(/script/valid_formdata\.js)
^<HOST> -.*(GET|POST|HEAD).*(/siteserver/login\.aspx)
^<HOST> -.*(GET|POST|HEAD).*(/siteserver/upgrade/default\.aspx)
^<HOST> -.*(GET|POST|HEAD).*(/site\.sql)
^<HOST> -.*(GET|POST|HEAD).*(/sql\.sql)
^<HOST> -.*(GET|POST|HEAD).*(soap:Envelope)
^<HOST> -.*(GET|POST|HEAD).*(/solr/admin/info/system)
^<HOST> -.*(GET|POST|HEAD).*(/stalker_portal/c)
^<HOST> -.*(GET|POST|HEAD).*(/stalker_portal/server/adm/tv-channels/iptv-list-json)
^<HOST> -.*(GET|POST|HEAD).*(/stalker_portal/server/adm/users/users-list-json)
^<HOST> -.*(GET|POST|HEAD).*(/stssys\.htm)
^<HOST> -.*(GET|POST|HEAD).*(/sys\.cache\.php)
^<HOST> -.*(GET|POST|HEAD).*(/system/assets/jquery/jquery-2\.x\.min\.js)
^<HOST> -.*(GET|POST|HEAD).*(/system_api\.php)
^<HOST> -.*(GET|POST|HEAD).*(/template/1/bluewise/_files/jspxcms\.css)
^<HOST> -.*(GET|POST|HEAD).*(/templates/jsn_glass_pro/ext/hikashop/jsn_ext_hikashop\.css)
^<HOST> -.*(GET|POST|HEAD).*(/test_404_page/)
^<HOST> -.*(GET|POST|HEAD).*(/test_for_404/)
^<HOST> -.*(GET|POST|HEAD).*(/temp\.sql)
^<HOST> -.*(GET|POST|HEAD).*(/translate\.sql)
^<HOST> -.*(GET|POST|HEAD).*(Test Wuz Here)
^<HOST> -.*(GET|POST|HEAD).*(/tmUnblock\.cgi)
^<HOST> -.*(GET|POST|HEAD).*(/tools/phpMyAdmin/index\.ph)
^<HOST> -.*(GET|POST|HEAD).*(/uc_server/control/admin/db\.php)
^<HOST> -.*(GET|POST|HEAD).*(/upload/bank-icons/)
^<HOST> -.*(GET|POST|HEAD).*(/UserCenter/css/admin/bgimg/admin_all_bg\.png)
^<HOST> -.*(GET|POST|HEAD).*(/\.user\.ini)
^<HOST> -.*(GET|POST|HEAD).*(\.bitcoin)
^<HOST> -.*(GET|POST|HEAD).*(wallet\.dat)
^<HOST> -.*(GET|POST|HEAD).*(bitcoin\.dat)
^<HOST> -.*(GET|POST|HEAD).*(/magento2/admin)
^<HOST> -.*(GET|POST|HEAD).*(/user/register?element_parents=account)
^<HOST> -.*(GET|POST|HEAD).*(/user/themes/antimatter/js/antimatter\.js)
^<HOST> -.*(GET|POST|HEAD).*(/user/themes/antimatter/js/modernizr\.custom\.71422\.js)
^<HOST> -.*(GET|POST|HEAD).*(/user/themes/antimatter/js/slidebars\.min\.js)
^<HOST> -.*(GET|POST|HEAD).*(/users\.sql)
^<HOST> -.*(GET|POST|HEAD).*(/vendor/phpunit/phpunit)
^<HOST> -.*(GET|POST|HEAD).*(/w00tw00t)
^<HOST> -.*(GET|POST|HEAD).*(/webbuilder/script/locale/wb-lang-zh_CN\.js)
^<HOST> -.*(GET|POST|HEAD).*(/web-console)
^<HOST> -.*(GET|POST|HEAD).*(/webdav)
^<HOST> -.*(GET|POST|HEAD).*(/web/phpMyAdmin/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(/whir_system/login\.aspx)
^<HOST> -.*(GET|POST|HEAD).*(/whir_system/module/security/login\.aspx)
^<HOST> -.*(GET|POST|HEAD).*(/wls-wsat/CoordinatorPortType)
^<HOST> -.*(GET|POST|HEAD).*(/wpbase/url\.php)
^<HOST> -.*(GET|POST|HEAD).*(/wp-content/plugins/)
^<HOST> -.*(GET|POST|HEAD).*(/wp-content/uploads/dump\.sql)
^<HOST> -.*(GET|POST|HEAD).*(/wp-includes/wlwmanifest\.xml)
^<HOST> -.*(GET|POST|HEAD).*(/wp-login\.php)
^<HOST> -.*(GET|POST|HEAD).*(/www/phpMyAdmin/index\.php)
^<HOST> -.*(GET|POST|HEAD).*(\x00Cookie:)
^<HOST> -.*(GET|POST|HEAD).*(\x22cache_name_function)
^<HOST> -.*(GET|POST|HEAD).*(\x22JDatabaseDriverMysqli)
^<HOST> -.*(GET|POST|HEAD).*(\x22JSimplepieFactory)
^<HOST> -.*(GET|POST|HEAD).*(\x22sanitize)
^<HOST> -.*(GET|POST|HEAD).*(\x22SimplePie)
^<HOST> -.*(GET|POST|HEAD).*(\x5C0disconnectHandlers)
^<HOST> -.*(GET).*(\.\./wp-config.php)
ignoreregex =

View File

@ -0,0 +1,17 @@
[geoipblocknginx]
enabled = true
port = http,https
filter = nginx-geoipblock
logpath = /var/log/nginx/geoipblock.log
maxretry = 1
findtime = 120m
bantime = 15m
[geoipblockssh]
enabled = true
port = ssh
filter = ssh-geoipblock
logpath = /var/log/syslog
maxretry = 1
findtime = 120m
bantime = 15m

View File

@ -0,0 +1,9 @@
[nginx-badbots]
enabled = true
port = http,https
filter = nginx-badbots
logpath = /var/log/nginx/access.log
maxretry = 2
[nginx-http-auth]
enabled = true

View File

@ -0,0 +1,8 @@
[webexploits]
enabled = true
port = http,https
filter = webexploits
logpath = /var/log/nginx/access.log
maxretry = 2
findtime = 240m
bantime = 60m

View File

@ -5,13 +5,16 @@
# Whitelist our own IP addresses. 127.0.0.1/8 is the default. But our status checks
# ping services over the public interface so we should whitelist that address of
# ours too. The string is substituted during installation.
ignoreip = 127.0.0.1/8 PUBLIC_IP
ignoreip = 127.0.0.1/8 PUBLIC_IP ADMIN_HOME_IP
bantime = 15m
findtime = 120m
maxretry = 4
[dovecot]
enabled = true
filter = dovecotimap
logpath = /var/log/mail.log
findtime = 30
findtime = 2m
maxretry = 20
[miab-management]
@ -20,7 +23,7 @@ filter = miab-management-daemon
port = http,https
logpath = /var/log/syslog
maxretry = 20
findtime = 30
findtime = 15m
[miab-munin]
enabled = true
@ -28,7 +31,7 @@ port = http,https
filter = miab-munin
logpath = /var/log/nginx/access.log
maxretry = 20
findtime = 30
findtime = 15m
[miab-owncloud]
enabled = true
@ -36,7 +39,7 @@ port = http,https
filter = miab-owncloud
logpath = STORAGE_ROOT/owncloud/nextcloud.log
maxretry = 20
findtime = 120
findtime = 15m
[miab-postfix587]
enabled = true
@ -44,7 +47,7 @@ port = 587
filter = miab-postfix-submission
logpath = /var/log/mail.log
maxretry = 20
findtime = 30
findtime = 2m
[miab-roundcube]
enabled = true
@ -52,11 +55,13 @@ port = http,https
filter = miab-roundcube
logpath = /var/log/roundcubemail/errors.log
maxretry = 20
findtime = 30
findtime = 15m
[recidive]
enabled = true
maxretry = 10
bantime = 2w
findtime = 3d
action = iptables-allports[name=recidive]
# In the recidive section of jail.conf the action contains:
#
@ -71,8 +76,17 @@ action = iptables-allports[name=recidive]
[postfix-sasl]
enabled = true
findtime = 7d
[postfix]
enabled = true
# postfix rbl also found by postfix jail, but postfix-rbl is more aggressive (maxretry = 1)
[postfix-rbl]
enabled = true
[sshd]
enabled = true
maxretry = 7
maxretry = 4
bantime = 3600
mode = aggressive

3
conf/geoiplookup.conf Normal file
View File

@ -0,0 +1,3 @@
# UPPERCASE space-separated country codes to ACCEPT
# See e.g. https://dev.maxmind.com/geoip/legacy/codes/iso3166/ for allowable codes
ALLOW_COUNTRIES=""

View File

@ -49,26 +49,6 @@
client_max_body_size 128M;
}
# Z-Push (Microsoft Exchange ActiveSync)
location /Microsoft-Server-ActiveSync {
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/local/lib/z-push/index.php;
fastcgi_param PHP_VALUE "include_path=.:/usr/share/php:/usr/share/pear:/usr/share/awl/inc";
fastcgi_read_timeout 630;
fastcgi_pass php-fpm;
# Outgoing mail also goes through this endpoint, so increase the maximum
# file upload limit to match the corresponding Postfix limit.
client_max_body_size 128M;
}
location ~* ^/autodiscover/autodiscover.xml$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/local/lib/z-push/autodiscover/autodiscover.php;
fastcgi_param PHP_VALUE "include_path=.:/usr/share/php:/usr/share/pear:/usr/share/awl/inc";
fastcgi_pass php-fpm;
}
# ADDITIONAL DIRECTIVES HERE
# Disable viewing dotfiles (.htaccess, .svn, .git, etc.)

View File

@ -7,6 +7,30 @@
rewrite ^/admin$ /admin/;
rewrite ^/admin/munin$ /admin/munin/ redirect;
location /admin/ {
# By default not blocked
set $block_test 1;
# block the continents
if ($allowed_continent = no) {
set $block_test 0;
}
# in addition, block the countries
if ($denied_country = no) {
set $block_test 0;
}
# allow some countries
if ($allowed_country = yes) {
set $block_test 1;
}
# if 0, then blocked
if ($block_test = 0) {
access_log /var/log/nginx/geoipblock.log geoipblock;
return 444;
}
proxy_pass http://127.0.0.1:10222/;
proxy_set_header X-Forwarded-For $remote_addr;
add_header X-Frame-Options "DENY";

View File

@ -7,6 +7,5 @@
## your own --- please do not ask for help from us.
upstream php-fpm {
server unix:/var/run/php/php7.2-fpm.sock;
server unix:/var/run/php/php{{phpver}}-fpm.sock;
}

View File

@ -0,0 +1,28 @@
# Expose this directory as static files.
root $ROOT;
index index.html index.htm;
location = /robots.txt {
log_not_found off;
access_log off;
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
# ADDITIONAL DIRECTIVES HERE
# Disable viewing dotfiles (.htaccess, .svn, .git, etc.)
# This block is placed at the end. Nginx's precedence rules means this block
# takes precedence over all non-regex matches and only regex matches that
# come after it (i.e. none of those, since this is the last one.) That means
# we're blocking dotfiles in the static hosted sites but not the FastCGI-
# handled locations for Nextcloud (which serves user-uploaded files that might
# have this pattern, see #414) or some of the other services.
location ~ /\.(ht|svn|git|hg|bzr) {
log_not_found off;
access_log off;
deny all;
}

View File

@ -0,0 +1,22 @@
# GeoIP databases
geoip_country /usr/share/GeoIP/GeoIP.dat;
geoip_city /usr/share/GeoIP/GeoIPCity.dat;
# map the list of denied countries
# see e.g. https://dev.maxmind.com/geoip/legacy/codes/iso3166/ for allowable
# countries
map $geoip_country_code $denied_country {
default yes;
}
# map the list of allowed countries
map $geoip_country_code $allowed_country {
default no;
}
# map the continents to allow
map $geoip_city_continent_code $allowed_continent {
default yes;
}
log_format geoipblock '[$time_local] - Geoip blocked $remote_addr';

View File

@ -0,0 +1,289 @@
<?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>

22
conf/solr/solr-jetty.xml Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<!-- Context configuration file for the Solr web application in Jetty -->
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/solr</Set>
<Set name="war">/usr/share/solr/web</Set>
<!-- Set the solr.solr.home system property -->
<Call name="setProperty" class="java.lang.System">
<Arg type="String">solr.solr.home</Arg>
<Arg type="String">/usr/share/solr</Arg>
</Call>
<!-- Enable symlinks -->
<!-- <Call name="addAliasCheck">
<Arg>
<New class="org.eclipse.jetty.server.handler.ContextHandler$ApproveSameSuffixAliases"/>
</Arg>
</Call>-->
</Configure>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<schema name="dovecot" 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.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>

20
conf/solr/solr.service Normal file
View File

@ -0,0 +1,20 @@
[Unit]
Description=Apache SOLR
After=network.target
[Service]
Type=forking
User=solr
Environment=SOLR_INCLUDE=/etc/default/solr.in.sh
ExecStart=/usr/local/lib/solr/bin/solr start
ExecStop=/usr/local/lib/solr/bin/solr stop
Restart=on-failure
#ReadWritePaths=/var/lib/solr/
#ReadWritePaths=/var/lib/solr/data/
LimitNOFILE=65000
LimitNPROC=65000
TimeoutSec=180s
PrivateTmp=true
[Install]
WantedBy=multi-user.target

View File

@ -12,7 +12,7 @@ import dateutil.parser, dateutil.relativedelta, dateutil.tz
import rtyaml
from exclusiveprocess import Lock
from utils import load_environment, shell, wait_for_service, fix_boto
from utils import load_environment, shell, wait_for_service, fix_boto, get_php_version
rsync_ssh_options = [
"--ssh-options= -i /root/.ssh/id_rsa_miab",
@ -20,7 +20,7 @@ rsync_ssh_options = [
]
def backup_status(env):
# If backups are dissbled, return no status.
# If backups are disabled, return no status.
config = get_backup_config(env)
if config["target"] == "off":
return { }
@ -212,9 +212,10 @@ def get_target_type(config):
def perform_backup(full_backup):
env = load_environment()
php_fpm = f"php{get_php_version()}-fpm"
# Create an global exclusive lock so that the backup script
# cannot be run more than one.
# cannot be run more than once.
Lock(die=True).forever()
config = get_backup_config(env)
@ -247,7 +248,7 @@ def perform_backup(full_backup):
if quit:
sys.exit(code)
service_command("php7.2-fpm", "stop", quit=True)
service_command(php_fpm, "stop", quit=True)
service_command("postfix", "stop", quit=True)
service_command("dovecot", "stop", quit=True)
@ -281,7 +282,7 @@ def perform_backup(full_backup):
# Start services again.
service_command("dovecot", "start", quit=False)
service_command("postfix", "start", quit=False)
service_command("php7.2-fpm", "start", quit=False)
service_command(php_fpm, "start", quit=False)
# Remove old backups. This deletes all backup data no longer needed
# from more than 3 days ago.
@ -316,6 +317,13 @@ def perform_backup(full_backup):
if get_target_type(config) == 'file':
shell('check_call', ["/bin/chown", "-R", env["STORAGE_USER"], backup_dir])
# Our nightly cron job executes system status checks immediately after this
# backup. Since it checks that dovecot and postfix are running, block for a
# bit (maximum of 10 seconds each) to give each a chance to finish restarting
# before the status checks might catch them down. See #381.
wait_for_service(25, True, env, 10)
wait_for_service(993, True, env, 10)
# Execute a post-backup script that does the copying to a remote server.
# Run as the STORAGE_USER user, not as root. Pass our settings in
# environment variables so the script has access to STORAGE_ROOT.
@ -325,13 +333,6 @@ def perform_backup(full_backup):
['su', env['STORAGE_USER'], '-c', post_script, config["target"]],
env=env)
# Our nightly cron job executes system status checks immediately after this
# backup. Since it checks that dovecot and postfix are running, block for a
# bit (maximum of 10 seconds each) to give each a chance to finish restarting
# before the status checks might catch them down. See #381.
wait_for_service(25, True, env, 10)
wait_for_service(993, True, env, 10)
def run_duplicity_verification():
env = load_environment()
backup_root = os.path.join(env["STORAGE_ROOT"], 'backup')

View File

@ -512,7 +512,10 @@ def web_get_domains():
@authorized_personnel_only
def web_update():
from web_update import do_web_update
return do_web_update(env)
try:
return do_web_update(env)
except Exception as e:
return (str(e), 500)
# System

View File

@ -13,6 +13,8 @@ export LC_TYPE=en_US.UTF-8
# sent and received so the admin might notice server abuse.
if [ `date "+%u"` -eq 1 ]; then
management/mail_log.py -t week | management/email_administrator.py "Mail-in-a-Box Usage Report"
pflogsumm -u 5 -h 5 --problems_first /var/log/mail.log.1 | management/email_administrator.py "Postfix log analysis summary"
fi
# Take a backup.

View File

@ -949,9 +949,9 @@ def get_secondary_dns(custom_dns, mode=None):
# doesn't.
if not hostname.startswith("xfr:"):
if mode == "xfr":
response = dns.resolver.query(hostname+'.', "A", raise_on_no_answer=False)
response = dns.resolver.resolve(hostname+'.', "A", raise_on_no_answer=False)
values.extend(map(str, response))
response = dns.resolver.query(hostname+'.', "AAAA", raise_on_no_answer=False)
response = dns.resolver.resolve(hostname+'.', "AAAA", raise_on_no_answer=False)
values.extend(map(str, response))
continue
values.append(hostname)
@ -974,7 +974,7 @@ def set_secondary_dns(hostnames, env):
if not item.startswith("xfr:"):
# Resolve hostname.
try:
response = resolver.query(item, "A")
response = resolver.resolve(item, "A")
except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
try:
response = resolver.query(item, "AAAA")

View File

@ -525,6 +525,9 @@ def get_required_aliases(env):
# The hostmaster alias is exposed in the DNS SOA for each zone.
aliases.add("hostmaster@" + env['PRIMARY_HOSTNAME'])
# Setup root alias
aliases.add("root@" + env['PRIMARY_HOSTNAME'])
# Get a list of domains we serve mail for, except ones for which the only
# email on that domain are the required aliases or a catch-all/domain-forwarder.
real_mail_domains = get_mail_domains(env,

View File

@ -110,6 +110,14 @@ def validate_auth_mfa(email, request, env):
if len(mfa_state) == 0:
return (True, [])
# munin routes are proxied by our control panel. We do not have
# full control over their routes so credentials are supplied via
# a basic HTTP authentication prompt.
# There is neither a way to input a mfa credential there nor can we pass
# the user_api_key from localStorage so mfa should be disabled for these routes.
if request.full_path.startswith("/munin"):
return (True, [])
# Try the enabled MFA modes.
hints = set()
for mfa_mode in mfa_state:

View File

@ -346,6 +346,8 @@ def provision_certificates(env, limit_domains):
"certonly",
#"-v", # just enough to see ACME errors
"--non-interactive", # will fail if user hasn't registered during Mail-in-a-Box setup
"--agree-tos", # Automatically agrees to Let's Encrypt TOS
"--register-unsafely-without-email", # The daemon takes care of renewals
"-d", ",".join(domain_list), # first will be main domain

View File

@ -40,6 +40,7 @@ def get_services():
{ "name": "Mail Filters (Sieve/dovecot)", "port": 4190, "public": True, },
{ "name": "HTTP Web (nginx)", "port": 80, "public": True, },
{ "name": "HTTPS Web (nginx)", "port": 443, "public": True, },
{ "name": "Solr Full Text Search (Jetty)", "port": 8983, "public": False, },
]
def run_checks(rounded_values, env, output, pool):
@ -735,7 +736,7 @@ def query_dns(qname, rtype, nxdomain='[Not Set]', at=None):
# Do the query.
try:
response = resolver.query(qname, rtype)
response = resolver.resolve(qname, rtype)
except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
# Host did not have an answer for this query; not sure what the
# difference is between the two exceptions.
@ -834,7 +835,7 @@ def what_version_is_this(env):
# Git may not be installed and Mail-in-a-Box may not have been cloned from github,
# so this function may raise all sorts of exceptions.
miab_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
tag = shell("check_output", ["/usr/bin/git", "describe", "--abbrev=0"], env={"GIT_DIR": os.path.join(miab_dir, '.git')}).strip()
tag = shell("check_output", ["/usr/bin/git", "describe", "--tags", "--abbrev=0"], env={"GIT_DIR": os.path.join(miab_dir, '.git')}).strip()
return tag
def get_latest_miab_version():
@ -857,16 +858,16 @@ def check_miab_version(env, output):
this_ver = "Unknown"
if config.get("privacy", True):
output.print_warning("You are running version Mail-in-a-Box %s. Mail-in-a-Box version check disabled by privacy setting." % this_ver)
output.print_warning("You are running version Mail-in-a-Box %s Kiekerjan Edition. Mail-in-a-Box version check disabled by privacy setting." % this_ver)
else:
latest_ver = get_latest_miab_version()
if this_ver == latest_ver:
output.print_ok("Mail-in-a-Box is up to date. You are running version %s." % this_ver)
output.print_ok("Mail-in-a-Box is up to date. You are running version %s Kiekerjan Edition." % this_ver)
elif latest_ver is None:
output.print_error("Latest Mail-in-a-Box version could not be determined. You are running version %s." % this_ver)
output.print_error("Latest Mail-in-a-Box version could not be determined. You are running version %s Kiekerjan Edition." % this_ver)
else:
output.print_error("A new version of Mail-in-a-Box is available. You are running version %s. The latest version is %s. For upgrade instructions, see https://mailinabox.email. "
output.print_error("A new version of Mail-in-a-Box is available. You are running version %s Kiekerjan Edition. The latest version is %s. For upgrade instructions, see https://mailinabox.email. "
% (this_ver, latest_ver))
def run_and_output_changes(env, pool):

View File

@ -182,6 +182,9 @@ def fix_boto():
import os
os.environ["BOTO_CONFIG"] = "/etc/boto3.cfg"
def get_php_version():
# Gets the version of PHP installed in the system.
return shell("check_output", ["/usr/bin/php", "-v"])[4:7]
if __name__ == "__main__":
from web_update import get_web_domains

View File

@ -7,7 +7,8 @@ import os.path, re, rtyaml
from mailconfig import get_mail_domains
from dns_update import get_custom_dns_config, get_dns_zones
from ssl_certificates import get_ssl_certificates, get_domain_ssl_files, check_certificate
from utils import shell, safe_domain_name, sort_domains
from utils import shell, safe_domain_name, sort_domains, get_php_version
from wwwconfig import get_www_domains
def get_web_domains(env, include_www_redirects=True, exclude_dns_elsewhere=True):
# What domains should we serve HTTP(S) for?
@ -18,11 +19,15 @@ def get_web_domains(env, include_www_redirects=True, exclude_dns_elsewhere=True)
# if the user wants to make one.
domains |= get_mail_domains(env)
# Add domains for which we only serve www
domains |= get_www_domains(domains)
if include_www_redirects:
# Add 'www.' subdomains that we want to provide default redirects
# to the main domain for. We'll add 'www.' to any DNS zones, i.e.
# the topmost of each domain we serve.
domains |= set('www.' + zone for zone, zonefile in get_dns_zones(env))
domains |= set('www.' + wwwdomain for wwwdomain in get_www_domains(get_mail_domains(env)))
# Add Autoconfiguration domains for domains that there are user accounts at:
# 'autoconfig.' for Mozilla Thunderbird auto setup.
@ -76,12 +81,14 @@ def do_web_update(env):
# Build an nginx configuration file.
nginx_conf = open(os.path.join(os.path.dirname(__file__), "../conf/nginx-top.conf")).read()
nginx_conf = re.sub("{{phpver}}", get_php_version(), nginx_conf)
# Load the templates.
template0 = open(os.path.join(os.path.dirname(__file__), "../conf/nginx.conf")).read()
template1 = open(os.path.join(os.path.dirname(__file__), "../conf/nginx-alldomains.conf")).read()
template2 = open(os.path.join(os.path.dirname(__file__), "../conf/nginx-primaryonly.conf")).read()
template3 = "\trewrite ^(.*) https://$REDIRECT_DOMAIN$1 permanent;\n"
template4 = open(os.path.join(os.path.dirname(__file__), "../conf/nginx-webonlydomains.conf")).read()
# Add the PRIMARY_HOST configuration first so it becomes nginx's default server.
nginx_conf += make_domain_config(env['PRIMARY_HOSTNAME'], [template0, template1, template2], ssl_certificates, env)
@ -89,6 +96,8 @@ def do_web_update(env):
# Add configuration all other web domains.
has_root_proxy_or_redirect = get_web_domains_with_root_overrides(env)
web_domains_not_redirect = get_web_domains(env, include_www_redirects=False)
web_only_domains = get_www_domains(get_mail_domains(env))
for domain in get_web_domains(env):
if domain == env['PRIMARY_HOSTNAME']:
# PRIMARY_HOSTNAME is handled above.
@ -96,7 +105,10 @@ def do_web_update(env):
if domain in web_domains_not_redirect:
# This is a regular domain.
if domain not in has_root_proxy_or_redirect:
nginx_conf += make_domain_config(domain, [template0, template1], ssl_certificates, env)
if domain in web_only_domains:
nginx_conf += make_domain_config(domain, [template0, template4], ssl_certificates, env)
else:
nginx_conf += make_domain_config(domain, [template0, template1], ssl_certificates, env)
else:
nginx_conf += make_domain_config(domain, [template0], ssl_certificates, env)
else:
@ -221,6 +233,10 @@ def get_web_root(domain, env, test_exists=True):
if os.path.exists(root) or not test_exists: break
return root
def is_default_web_root(domain, env):
root = os.path.join(env["STORAGE_ROOT"], "www", safe_domain_name(domain))
return not os.path.exists(root)
def get_web_domains_info(env):
www_redirects = set(get_web_domains(env)) - set(get_web_domains(env, include_www_redirects=False))
has_root_proxy_or_redirect = set(get_web_domains_with_root_overrides(env))

34
management/wwwconfig.py Normal file
View File

@ -0,0 +1,34 @@
import os.path, idna, sys, collections
def get_www_domains(domains_to_skip):
# Returns the domain names (IDNA-encoded) of all of the domains that are configured to serve www
# on the system.
domains = []
try:
# read a line from text file
with open("/etc/miabwwwdomains.conf") as file_in:
for line in file_in:
# Valid domain check future extention: use validators module
# Only one dot allowed
if line.count('.') == 1:
www_domain = get_domain(line, as_unicode=False)
if www_domain not in domains_to_skip:
domains.append(www_domain)
except:
# ignore failures
pass
return set(domains)
def get_domain(domaintxt, as_unicode=True):
ret = domaintxt.rstrip()
if as_unicode:
try:
ret = idna.decode(ret.encode('ascii'))
except (ValueError, UnicodeError, idna.IDNAError):
pass
return ret

27
setup/additionals.sh Normal file
View File

@ -0,0 +1,27 @@
source /etc/mailinabox.conf
source setup/functions.sh
# Add additional packages
apt_install pflogsumm
# Cleanup old spam and trash email
hide_output install -m 755 conf/cron/miab_clean_mail /etc/cron.weekly/
# Reduce logs by not logging mail output in syslog
sed -i "s/\*\.\*;auth,authpriv.none.*\-\/var\/log\/syslog/\*\.\*;mail,auth,authpriv.none \-\/var\/log\/syslog/g" /etc/rsyslog.d/50-default.conf
# Reduce logs by only logging ufw in ufw.log
sed -i "s/#\& stop/\& stop/g" /etc/rsyslog.d/20-ufw.conf
restart_service rsyslog
# decrease time journal is stored
tools/editconf.py /etc/systemd/journald.conf MaxRetentionSec=2month
tools/editconf.py /etc/systemd/journald.conf MaxFileSec=1week
hide_output systemctl restart systemd-journald.service
# Create forward for root emails
cat > /root/.forward << EOF;
administrator@$PRIMARY_HOSTNAME
EOF

View File

@ -18,9 +18,13 @@ if [ -z "$TAG" ]; then
# space, but if we put it in a comment it would confuse the status checks!)
# to get the latest version, so the first such line must be the one that we
# want to display in status checks.
if [ "`lsb_release -d | sed 's/.*:\s*//' | sed 's/18\.04\.[0-9]/18.04/' `" == "Ubuntu 18.04 LTS" ]; then
if [ "`lsb_release -d | sed 's/.*:\s*//' | sed 's/20\.04\.[0-9]/20.04/' `" == "Ubuntu 20.04 LTS" ]; then
# This machine is running Ubuntu 20.04.
TAG=v0.53
elif [ "`lsb_release -d | sed 's/.*:\s*//' | sed 's/18\.04\.[0-9]/18.04/' `" == "Ubuntu 18.04 LTS" ]; then
# This machine is running Ubuntu 18.04.
TAG=v0.52
TAG=v0.53
elif [ "`lsb_release -d | sed 's/.*:\s*//' | sed 's/14\.04\.[0-9]/14.04/' `" == "Ubuntu 14.04 LTS" ]; then
# This machine is running Ubuntu 14.04.
@ -34,7 +38,7 @@ if [ -z "$TAG" ]; then
TAG=v0.30
else
echo "This script must be run on a system running Ubuntu 18.04 or Ubuntu 14.04."
echo "This script must be run on a system running Ubuntu 20.04, 18.04 or 14.04."
exit 1
fi
fi
@ -68,7 +72,7 @@ fi
cd $HOME/mailinabox
# Update it.
if [ "$TAG" != `git describe` ]; then
if [ "$TAG" != "`git describe --tags`" ]; then
echo Updating Mail-in-a-Box to $TAG . . .
git fetch --depth 1 --force --prune origin tag $TAG
if ! git checkout -q $TAG; then

View File

@ -16,11 +16,15 @@ source /etc/mailinabox.conf # load global vars
# * ldnsutils: Helper utilities for signing DNSSEC zones.
# * openssh-client: Provides ssh-keyscan which we use to create SSHFP records.
echo "Installing nsd (DNS server)..."
apt_install nsd ldnsutils openssh-client
apt_install ldnsutils openssh-client
# Prepare nsd's configuration.
mkdir -p /var/run/nsd
mkdir -p /etc/nsd
mkdir -p /etc/nsd/zones
touch /etc/nsd/zones.conf
touch /etc/nsd/nsd.conf
cat > /etc/nsd/nsd.conf << EOF;
# Do not edit. Overwritten by Mail-in-a-Box setup.
@ -64,6 +68,17 @@ done
echo "include: /etc/nsd/zones.conf" >> /etc/nsd/nsd.conf;
# Add systemd override file to fix some permissions
mkdir -p /etc/systemd/system/nsd.service.d/
cat > /etc/systemd/system/nsd.service.d/nsd-permissions.conf << EOF
[Service]
ReadWritePaths=/var/lib/nsd /etc/nsd /run /var/log /run/nsd
CapabilityBoundingSet=CAP_CHOWN CAP_IPC_LOCK CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_NET_ADMIN
EOF
# Attempting a late install of nsd (after configuration)
apt_install nsd
# Create DNSSEC signing keys.
mkdir -p "$STORAGE_ROOT/dns/dnssec";

View File

@ -221,3 +221,7 @@ function git_clone {
mv $TMPPATH/$SUBDIR $TARGETPATH
rm -rf $TMPPATH
}
function php_version {
php --version | head -n 1 | cut -d " " -f 2 | cut -c 1-3
}

41
setup/geoipfilter.sh Normal file
View File

@ -0,0 +1,41 @@
#!/bin/bash
CONFIG_FILE=/etc/geoiplookup.conf
GEOIPLOOKUP=/usr/local/bin/goiplookup
# Check existence of configuration
if [ -f "$CONFIG_FILE" ]; then
source $CONFIG_FILE
# Check required variable exists and is non-empty
if [ -z "$ALLOW_COUNTRIES" ]; then
echo "variable ALLOW_COUNTRIES is not set or empty. No countries are blocked."
exit 0
fi
else
echo "Configuration $CONFIG_FILE does not exist. No countries are blocked."
exit 0
fi
# Check existence of binary
if [ ! -x "$GEOIPLOOKUP" ]; then
echo "Geoip lookup binary $GEOIPLOOKUP does not exist. No countries are blocked."
exit 0
fi
if [ $# -ne 1 -a $# -ne 2 ]; then
echo "Usage: `basename $0` <ip>" 1>&2
exit 0 # return true in case of config issue
fi
COUNTRY=`$GEOIPLOOKUP $1 | awk -F ": " '{ print $2 }' | awk -F "," '{ print $1 }' | head -n 1`
[[ $COUNTRY = "IP Address not found" || $ALLOW_COUNTRIES =~ $COUNTRY ]] && RESPONSE="ALLOW" || RESPONSE="DENY"
logger "$RESPONSE geoipblocked connection from $1 ($COUNTRY) $2"
if [ $RESPONSE = "ALLOW" ]
then
exit 0
else
exit 1
fi

104
setup/geoiptoolssetup.sh Normal file
View File

@ -0,0 +1,104 @@
#!/bin/bash
source setup/functions.sh
echo Installing geoip packages...
# geo ip filtering of ssh entries, based on https://www.axllent.org/docs/ssh-geoip/#disqus_thread
# Install geo ip lookup tool
gunzip -c tools/goiplookup.gz > /usr/local/bin/goiplookup
chmod +x /usr/local/bin/goiplookup
# check that GeoLite2-Country.mmdb is older then 2 months, to not hit the server too often
if [[ ! -d /usr/share/GeoIP || ! -f /usr/share/GeoIP/GeoLite2-Country.mmdb || $(find "/usr/share/GeoIP/GeoLite2-Country.mmdb" -mtime +60 -print) ]]; then
echo updating goiplookup database
goiplookup db-update
else
echo skipping goiplookup database update
fi
# Install geo ip filter script
cp -f setup/geoipfilter.sh /usr/local/bin/
chmod +x /usr/local/bin/geoipfilter.sh
# Install only if not yet exists, to keep user config
if [ ! -f /etc/geoiplookup.conf ]; then
cp -f conf/geoiplookup.conf /etc/
fi
# Add sshd entries for hosts.deny and hosts.allow
if grep -Fxq "sshd: ALL" /etc/hosts.deny
then
echo hosts.deny already configured
else
sed -i '/sshd: /d' /etc/hosts.deny
echo "sshd: ALL" >> /etc/hosts.deny
fi
if grep -Fxq "sshd: ALL: aclexec /usr/local/bin/geoipfilter.sh %a %s" /etc/hosts.allow
then
echo hosts.allow already configured
else
# Make sure all sshd lines are removed
sed -i '/sshd: /d' /etc/hosts.allow
echo "sshd: ALL: aclexec /usr/local/bin/geoipfilter.sh %a %s" >> /etc/hosts.allow
fi
# geo ip filtering of nginx access log, based on
# https://guides.wp-bullet.com/blocking-country-and-continent-with-nginx-geoip-on-ubuntu-18-04/
## Install geo ip lookup files
# check that GeoIP.dat is older then 2 months, to not hit the server too often
if [[ ! -d /usr/share/GeoIP || ! -f /usr/share/GeoIP/GeoIP.dat || $(find "/usr/share/GeoIP/GeoIP.dat" -mtime +60 -print) ]]; then
echo updating GeoIP database
# Move old file away if it exists
if [ -f "/usr/share/GeoIP/GeoIP.dat" ]; then
mv -f /usr/share/GeoIP/GeoIP.dat /usr/share/GeoIP/GeoIP.dat.bak
fi
hide_output wget -P /usr/share/GeoIP/ https://dl.miyuru.lk/geoip/maxmind/country/maxmind.dat.gz
if [ -f "/usr/share/GeoIP/maxmind.dat.gz" ]; then
gunzip -c /usr/share/GeoIP/maxmind.dat.gz > /usr/share/GeoIP/GeoIP.dat
rm -f /usr/share/GeoIP/maxmind.dat.gz
else
echo Did not correctly download maxmind geoip country database
fi
# If new file is not created, move the old file back
if [ ! -f "/usr/share/GeoIP/GeoIP.dat" ]; then
echo GeoIP.dat was not created
if [ -f "/usr/share/GeoIP/GeoIP.dat.bak" ]; then
mv /usr/share/GeoIP/GeoIP.dat.bak /usr/share/GeoIP/GeoIP.dat
fi
fi
# Move old file away if it exists
if [ -f "/usr/share/GeoIP/GeoIPCity.dat" ]; then
mv -f /usr/share/GeoIP/GeoIPCity.dat /usr/share/GeoIP/GeoIPCity.dat.bak
fi
hide_output wget -P /usr/share/GeoIP/ https://dl.miyuru.lk/geoip/maxmind/city/maxmind.dat.gz
if [ -f "/usr/share/GeoIP/maxmind.dat.gz" ]; then
gunzip -c /usr/share/GeoIP/maxmind.dat.gz > /usr/share/GeoIP/GeoIPCity.dat
rm -f /usr/share/GeoIP/maxmind.dat.gz
else
echo Did not correctly download maxmind geoip city database
fi
# If new file is not created, move the old file back
if [ ! -f "/usr/share/GeoIP/GeoIPCity.dat" ]; then
echo GeoIPCity.dat was not created
if [ -f "/usr/share/GeoIP/GeoIPCity.dat.bak" ]; then
mv /usr/share/GeoIP/GeoIPCity.dat.bak /usr/share/GeoIP/GeoIPCity.dat
fi
fi
else
echo skipping GeoIP database update
fi

View File

@ -137,6 +137,14 @@ tools/editconf.py /etc/postfix/main.cf \
tls_preempt_cipherlist=no \
smtpd_tls_received_header=yes
# Add block_root_external to block mail send to root@PRIMARY_HOSTNAME. This mail address is only supposed to be used for local
# mail delivery (cron etc)
cat > /etc/postfix/block_root_external << EOF;
root@$PRIMARY_HOSTNAME REJECT
EOF
postmap /etc/postfix/block_root_external
# Prevent non-authenticated users from sending mail that requires being
# relayed elsewhere. We don't want to be an "open relay". On outbound
# mail, require one of:
@ -144,9 +152,10 @@ tools/editconf.py /etc/postfix/main.cf \
# * `permit_sasl_authenticated`: Authenticated users (i.e. on port 587).
# * `permit_mynetworks`: Mail that originates locally.
# * `reject_unauth_destination`: No one else. (Permits mail whose destination is local and rejects other mail.)
# * `block_root_external`: Block mail addressed at root@PRIMARY_HOSTNAME. Root mail is only to receive mails locally send to root.
# permit_mynetworks will allow delivery of mail for root originating locally.
tools/editconf.py /etc/postfix/main.cf \
smtpd_relay_restrictions=permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination
smtpd_relay_restrictions=permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination,hash:/etc/postfix/block_root_external
# ### DANE

View File

@ -25,7 +25,7 @@ done
#
# certbot installs EFF's certbot which we use to
# provision free TLS certificates.
apt_install duplicity python-pip virtualenv certbot
apt_install duplicity python3-pip virtualenv certbot
# b2sdk is used for backblaze backups.
# boto is used for amazon aws backups.

View File

@ -23,14 +23,15 @@ includedir /etc/munin/munin-conf.d
# path dynazoom uses for requests
cgiurl_graph /admin/munin/cgi-graph
# send alerts to the following address
contact.admin.command mail -s "Munin notification \${var:host}" administrator@$PRIMARY_HOSTNAME
contact.admin.always_send warning critical
# a simple host tree
[$PRIMARY_HOSTNAME]
address 127.0.0.1
# send alerts to the following address
contacts admin
contact.admin.command mail -s "Munin notification \${var:host}" administrator@$PRIMARY_HOSTNAME
contact.admin.always_send warning critical
EOF
# The Debian installer touches these files and chowns them to www-data:adm for use with spawn-fcgi
@ -70,6 +71,23 @@ hide_output systemctl daemon-reload
hide_output systemctl unmask munin.service
hide_output systemctl enable munin.service
# Some more munin plugins
if [ -f /usr/share/munin/plugins/postfix_mailstats ] && [ ! -h /etc/munin/plugins/postfix_mailstats ]; then
ln -fs /usr/share/munin/plugins/postfix_mailstats /etc/munin/plugins/
fi
if [ -f /usr/share/munin/plugins/spamstats ] && [ ! -h /etc/munin/plugins/spamstats ]; then
ln -fs /usr/share/munin/plugins/spamstats /etc/munin/plugins/
fi
if [ -f /usr/share/munin/plugins/df_abs ] && [ ! -h /etc/munin/plugins/df_abs ]; then
ln -fs /usr/share/munin/plugins/df_abs /etc/munin/plugins/
fi
if [ -f /usr/share/munin/plugins/fail2ban ] && [ ! -h /etc/munin/plugins/fail2ban ]; then
ln -fs /usr/share/munin/plugins/fail2ban /etc/munin/plugins/
fi
# Restart services.
restart_service munin
restart_service munin-node

View File

@ -42,6 +42,9 @@ InstallNextcloud() {
mv /usr/local/lib/nextcloud /usr/local/lib/owncloud
rm -f /tmp/nextcloud.zip
# Empty the skeleton dir to save some space for each new user
rm -rf /usr/local/lib/owncloud/core/skeleton/*
# The two apps we actually want are not in Nextcloud core. Download the releases from
# their github repositories.
mkdir -p /usr/local/lib/owncloud/apps
@ -97,12 +100,12 @@ InstallNextcloud() {
}
# Nextcloud Version to install. Checks are done down below to step through intermediate versions.
nextcloud_ver=20.0.1
nextcloud_hash=f2b3faa570c541df73f209e873a1c2852e79eab8
contacts_ver=3.4.1
contacts_hash=aee680a75e95f26d9285efd3c1e25cf7f3bfd27e
calendar_ver=2.1.2
calendar_hash=930c07863bb7a65652dec34793802c8d80502336
nextcloud_ver=20.0.8
nextcloud_hash=372b0b4bb07c7984c04917aff86b280e68fbe761
contacts_ver=3.5.1
contacts_hash=d2ffbccd3ed89fa41da20a1dff149504c3b33b93
calendar_ver=2.1.3
calendar_hash=d7d9db0e55ff1c9c2a2356e8980a8d9fce3fc4a0
user_external_ver=1.0.0
user_external_hash=3bf2609061d7214e7f0f69dd8883e55c4ec8f50a
@ -124,7 +127,7 @@ fi
if [ ! -d /usr/local/lib/owncloud/ ] || [[ ! ${CURRENT_NEXTCLOUD_VER} =~ ^$nextcloud_ver ]]; then
# Stop php-fpm if running. If theyre not running (which happens on a previously failed install), dont bail.
service php7.2-fpm stop &> /dev/null || /bin/true
service php$(php_version)-fpm stop &> /dev/null || /bin/true
# Backup the existing ownCloud/Nextcloud.
# Create a backup directory to store the current installation and database to
@ -316,7 +319,7 @@ sudo -u www-data php /usr/local/lib/owncloud/occ app:disable photos dashboard ac
# Set PHP FPM values to support large file uploads
# (semicolon is the comment character in this file, hashes produce deprecation warnings)
tools/editconf.py /etc/php/7.2/fpm/php.ini -c ';' \
tools/editconf.py /etc/php/$(php_version)/fpm/php.ini -c ';' \
upload_max_filesize=16G \
post_max_size=16G \
output_buffering=16384 \
@ -325,7 +328,7 @@ tools/editconf.py /etc/php/7.2/fpm/php.ini -c ';' \
short_open_tag=On
# Set Nextcloud recommended opcache settings
tools/editconf.py /etc/php/7.2/cli/conf.d/10-opcache.ini -c ';' \
tools/editconf.py /etc/php/$(php_version)/cli/conf.d/10-opcache.ini -c ';' \
opcache.enable=1 \
opcache.enable_cli=1 \
opcache.interned_strings_buffer=8 \
@ -335,8 +338,8 @@ tools/editconf.py /etc/php/7.2/cli/conf.d/10-opcache.ini -c ';' \
opcache.revalidate_freq=1
# If apc is explicitly disabled we need to enable it
if grep -q apc.enabled=0 /etc/php/7.2/mods-available/apcu.ini; then
tools/editconf.py /etc/php/7.2/mods-available/apcu.ini -c ';' \
if grep -q apc.enabled=0 /etc/php/$(php_version)/mods-available/apcu.ini; then
tools/editconf.py /etc/php/$(php_version)/mods-available/apcu.ini -c ';' \
apc.enabled=1
fi
@ -361,4 +364,4 @@ rm -f /etc/cron.hourly/mailinabox-owncloud
# ```
# Enable PHP modules and restart PHP.
restart_service php7.2-fpm
restart_service php$(php_version)-fpm

View File

@ -7,9 +7,10 @@ if [[ $EUID -ne 0 ]]; then
exit 1
fi
# Check that we are running on Ubuntu 18.04 LTS (or 18.04.xx).
if [ "`lsb_release -d | sed 's/.*:\s*//' | sed 's/18\.04\.[0-9]/18.04/' `" != "Ubuntu 18.04 LTS" ]; then
echo "Mail-in-a-Box only supports being installed on Ubuntu 18.04, sorry. You are running:"
# Check that we are running on Debian GNU/Linux, or Ubuntu 20.04
OS=`lsb_release -d | sed 's/.*:\s*//'`
if [ "$OS" != "Debian GNU/Linux 10 (buster)" -a "$(echo $OS | grep -o 'Ubuntu 20.04')" != "Ubuntu 20.04" ]; then
echo "Mail-in-a-Box only supports being installed on Debian 10 or Ubuntu 20.04 LTS, sorry. You are running:"
echo
lsb_release -d | sed 's/.*:\s*//'
echo

View File

@ -9,7 +9,7 @@ if [ -z "${NONINTERACTIVE:-}" ]; then
if [ ! -f /usr/bin/dialog ] || [ ! -f /usr/bin/python3 ] || [ ! -f /usr/bin/pip3 ]; then
echo Installing packages needed for setup...
apt-get -q -q update
apt_get_quiet install dialog python3 python3-pip || exit 1
apt_get_quiet install dialog file python3 python3-pip || exit 1
fi
# Installing email_validator is repeated in setup/management.sh, but in setup/management.sh
@ -119,6 +119,24 @@ if [ -z "${PUBLIC_IP:-}" ]; then
fi
fi
if [ -z "${ADMIN_HOME_IP:-}" ]; then
if [ -z "${DEFAULT_ADMIN_HOME_IP:-}" ]; then
input_box "Admin Home IP Address" \
"Enter the public IP address of the admin home, as given to you by your ISP.
This will be used to prevent banning of the administrator IP address.
\n\nAdmin Home IP address:" \
"" \
ADMIN_HOME_IP
else
ADMIN_HOME_IP=$DEFAULT_ADMIN_HOME_IP
fi
fi
if [ -z "${ADMIN_HOME_IP:-}" ]; then
ADMIN_HOME_IP=""
fi
# Same for IPv6. But it's optional. Also, if it looks like the system
# doesn't have an IPv6, don't ask for one.
if [ -z "${PUBLIC_IPV6:-}" ]; then
@ -206,7 +224,10 @@ fi
if [ "$PRIVATE_IPV6" != "$PUBLIC_IPV6" ]; then
echo "Private IPv6 Address: $PRIVATE_IPV6"
fi
if [ -n "$ADMIN_HOME_IP" ]; then
echo "Admin Home IP Address: $ADMIN_HOME_IP"
fi
if [ -f /usr/bin/git ] && [ -d .git ]; then
echo "Mail-in-a-Box Version: " $(git describe)
echo "Mail-in-a-Box Version: " $(git describe --tags)
fi
echo

166
setup/solr.sh Normal file
View File

@ -0,0 +1,166 @@
#!/bin/bash
#
# IMAP search with lucene via solr
# --------------------------------
#
# By default dovecot uses its own Squat search index that has awful performance
# on large mailboxes. Dovecot 2.1+ has support for using Lucene internally but
# this didn't make it into the Ubuntu packages, so we use Solr instead to run
# Lucene for us.
#
# Solr runs as a Jetty process. The dovecot solr plugin talks to solr via its
# HTTP interface, searching indexed mail and returning results back to dovecot.
#
# Based on https://forum.iredmail.org/topic17251-dovecot-fts-full-text-search-using-apache-solr-on-ubuntu-1804-lts.html
# https://doc.dovecot.org/configuration_manual/fts/solr/ and https://solr.apache.org/guide/8_8/installing-solr.html
#
# solr-jetty package is removed from Ubuntu 21.04 onward. This installation
# therefore depends on manual installation of solr instead of an ubuntu package
source setup/functions.sh # load our functions
source /etc/mailinabox.conf # load global vars
# Install packages and basic configuation
# ---------------------------------------
echo "Installing Solr..."
apt_install dovecot-solr default-jre-headless
VERSION=8.8.2
HASH=7c3e2ed31a4412e7dac48d68c3abd52f75684577
needs_update=0
if [ ! -f /usr/local/lib/solr/bin/solr ]; then
# not installed yet
needs_update=1
elif [[ "$VERSION" != `/usr/local/lib/solr/bin/solr version` ]]; then
# checks if the version is what we want
needs_update=1
fi
if [ $needs_update == 1 ]; then
# install SOLR
wget_verify \
"https://www.apache.org/dyn/closer.lua?action=download&filename=lucene/solr/$VERSION/solr-$VERSION.tgz" \
$HASH \
/tmp/solr.tgz
tar xzf /tmp/solr-$VERSION.tgz -C /tmp solr-$VERSION/bin/install_solr_service.sh --strip-components=2
# install to usr/local, force update, do not start service on installation complete
bash /tmp/install_solr_service.sh /tmp/solr-$VERSION.tgz -i /usr/local/lib -f -n
rm -f /tmp/solr-$VERSION.tgz
rm -f /tmp/install_solr_service.sh
# stop and remove the init.d script
rm -f /etc/init.d/solr
update-rc.d solr remove
fi
# Add security
tools/editconf.py /etc/default/solr.in.sh \
SOLR_IP_WHITELIST="127.0.0.1, [::1]"
# Change log dir
if [! -d "/var/log/solr" ]; then
mkdir /var/log/solr
fi
chown solr:solr /var/log/solr
tools/editconf.py /etc/default/solr.in.sh \
SOLR_LOGS_DIR="/var/log/solr"
# Install systemd service
cp -f conf/solr/solr.service /lib/systemd/system/solr.service
# hide_output systemctl link -f /lib/systemd/system/solr.service
# Reload systemctl to pickup the above changes
hide_output systemctl daemon-reload
# Make sure service is enabled
hide_output systemctl enable solr.service
# Update the dovecot plugin configuration
#
# Break-imap-search makes search work the way users expect, rather than the way
# the IMAP specification expects.
# https://wiki.dovecot.org/Plugins/FTS/Solr
# "break-imap-search : Use Solr also for indexing TEXT and BODY searches.
# This makes your server non-IMAP-compliant."
tools/editconf.py /etc/dovecot/conf.d/10-mail.conf \
mail_plugins="fts fts_solr"
cat > /etc/dovecot/conf.d/90-plugin-fts.conf << EOF;
plugin {
fts = solr
fts_autoindex = yes
fts_solr = url=http://127.0.0.1:8983/solr/dovecot/
}
EOF
# Install cronjobs to keep FTS up to date.
hide_output install -m 755 conf/cron/miab_dovecot /etc/cron.daily/
hide_output install -m 644 conf/cron/miab_solr /etc/cron.d/
# Initialize solr dovecot instance
if [ ! -d "/var/solr/data/dovecot" ]; then
# Starting solr might take a while
echo "Starting solr..."
hide_output systemctl restart solr.service
sudo -u solr /usr/local/lib/solr/bin/solr create -c dovecot
rm -f /var/solr/data/dovecot/conf/schema.xml
rm -f /var/solr/data/dovecot/conf/managed-schema
rm -f /var/solr/data/dovecot/conf/solrconfig.xml
cp -f conf/solr/solr-config-7.7.0.xml /var/solr/data/dovecot/conf/solrconfig.xml
cp -f conf/solr/solr-schema-7.7.0.xml /var/solr/data/dovecot/conf/schema.xml
chown -R solr:solr /var/solr/data/dovecot/conf/*
fi
# Create new rsyslog config for solr
cat > /etc/rsyslog.d/10-solr.conf <<EOF
# Send solr systemd messages to solr-systemd.log when using systemd
:programname, startswith, "solr" {
/var/log/solr-systemd.log
stop
}
EOF
# Also adjust logrotated to the new file and correct user
cat > /etc/logrotate.d/solr-systemd <<EOF
/var/log/solr-systemd.log {
rotate 4
weekly
missingok
notifempty
compress
delaycompress
create 640 syslog adm
}
EOF
# Restart services to reload solr schema, dovecot plugins and rsyslog changes
restart_service dovecot
restart_service rsyslog
# Restarting solr might take a while
echo "Restarting solr"
hide_output systemctl restart solr.service
# Kickoff building the index
# Per doveadm-fts manpage: Scan what mails exist in the full text search index
# and compare those to what actually exist in mailboxes.
# This removes mails from the index that have already been expunged and makes
# sure that the next doveadm index will index all the missing mails (if any).
doveadm fts rescan -A
# Adds unindexed files to the fts database
# * `-q`: Queues the indexing to be run by indexer process. (will background the indexing)
# * `-A`: All users
# * `'*'`: All folders
doveadm index -q -A '*'

View File

@ -195,3 +195,4 @@ chmod 770 $STORAGE_ROOT/mail/spamassassin
restart_service spampd
restart_service dovecot
systemctl enable spamassassin.service

View File

@ -14,9 +14,14 @@ source setup/preflight.sh
# Python may not be able to read/write files. This is also
# in the management daemon startup script and the cron script.
# Make sure we have locales at all (some images are THAT minimal)
apt_get_quiet install locales
if ! locale -a | grep en_US.utf8 > /dev/null; then
echo "Generating locales..."
# Generate locale if not exists
hide_output locale-gen en_US.UTF-8
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
hide_output locale-gen
fi
export LANGUAGE=en_US.UTF-8
@ -95,23 +100,27 @@ PUBLIC_IPV6=$PUBLIC_IPV6
PRIVATE_IP=$PRIVATE_IP
PRIVATE_IPV6=$PRIVATE_IPV6
MTA_STS_MODE=${MTA_STS_MODE-}
ADMIN_HOME_IP=$ADMIN_HOME_IP
EOF
# Start service configuration.
source setup/system.sh
source setup/geoiptoolssetup.sh
source setup/ssl.sh
source setup/dns.sh
source setup/mail-postfix.sh
source setup/mail-dovecot.sh
source setup/mail-users.sh
#source setup/solr.sh
source setup/dkim.sh
source setup/spamassassin.sh
source setup/web.sh
source setup/webmail.sh
source setup/nextcloud.sh
source setup/zpush.sh
#source setup/zpush.sh
source setup/management.sh
source setup/munin.sh
source setup/additionals.sh
# Wait for the management daemon to start...
until nc -z -w 4 127.0.0.1 10222

View File

@ -75,26 +75,7 @@ then
fi
fi
# ### Add PPAs.
# We install some non-standard Ubuntu packages maintained by other
# third-party providers. First ensure add-apt-repository is installed.
if [ ! -f /usr/bin/add-apt-repository ]; then
echo "Installing add-apt-repository..."
hide_output apt-get update
apt_install software-properties-common
fi
# Ensure the universe repository is enabled since some of our packages
# come from there and minimal Ubuntu installs may have it turned off.
hide_output add-apt-repository -y universe
# Install the certbot PPA.
hide_output add-apt-repository -y ppa:certbot/certbot
# Install the duplicity PPA.
hide_output add-apt-repository -y ppa:duplicity-team/duplicity-release-git
# Certbot doesn't require a PPA in Debian
# ### Update Packages
@ -258,20 +239,21 @@ if [ -z "${DISABLE_FIREWALL:-}" ]; then
# Install `ufw` which provides a simple firewall configuration.
apt_install ufw
# Allow incoming connections to SSH.
ufw_limit ssh;
# ssh might be running on an alternate port. Use sshd -T to dump sshd's #NODOC
# settings, find the port it is supposedly running on, and open that port #NODOC
# too. #NODOC
SSH_PORT=$(sshd -T 2>/dev/null | grep "^port " | sed "s/port //") #NODOC
if [ ! -z "$SSH_PORT" ]; then
if [ "$SSH_PORT" != "22" ]; then
echo Opening alternate SSH port $SSH_PORT. #NODOC
ufw_limit $SSH_PORT #NODOC
fi
if [ "$SSH_PORT" != "22" ]; then
echo Opening alternate SSH port $SSH_PORT. #NODOC
ufw_limit $SSH_PORT #NODOC
else
# Allow incoming connections to SSH.
ufw_limit ssh;
fi
else
# Allow incoming connections to SSH.
ufw_limit ssh;
fi
ufw --force enable;
@ -324,12 +306,21 @@ fi #NODOC
# If more queries than specified are sent, bind9 returns SERVFAIL. After flushing the cache during system checks,
# we ran into the limit thus we are increasing it from 75 (default value) to 100.
apt_install bind9
touch /etc/default/bind9
tools/editconf.py /etc/default/bind9 \
"OPTIONS=\"-u bind -4\""
if ! grep -q "listen-on " /etc/bind/named.conf.options; then
# Add a listen-on directive if it doesn't exist inside the options block.
sed -i "s/^}/\n\tlisten-on { 127.0.0.1; };\n}/" /etc/bind/named.conf.options
fi
if ! grep -q "listen-on-v6 " /etc/bind/named.conf.options; then
# Add a listen-on-v6 directive if it doesn't exist inside the options block.
sed -i "s/^}/\n\tlisten-on-v6 { ::1; };\n}/" /etc/bind/named.conf.options
else
# Modify the listen-on-v6 directive if it does exist
sed -i "s/listen-on-v6 { any; }/listen-on-v6 { ::1; }/" /etc/bind/named.conf.options
fi
if ! grep -q "max-recursion-queries " /etc/bind/named.conf.options; then
# Add a max-recursion-queries directive if it doesn't exist inside the options block.
sed -i "s/^}/\n\tmax-recursion-queries 100;\n}/" /etc/bind/named.conf.options
@ -357,9 +348,14 @@ rm -f /etc/fail2ban/jail.local # we used to use this file but don't anymore
rm -f /etc/fail2ban/jail.d/defaults-debian.conf # removes default config so we can manage all of fail2ban rules in one config
cat conf/fail2ban/jails.conf \
| sed "s/PUBLIC_IP/$PUBLIC_IP/g" \
| sed "s/ADMIN_HOME_IP/$ADMIN_HOME_IP/g" \
| sed "s#STORAGE_ROOT#$STORAGE_ROOT#" \
> /etc/fail2ban/jail.d/mailinabox.conf
> /etc/fail2ban/jail.d/00-mailinabox.conf
cp -f conf/fail2ban/filter.d/* /etc/fail2ban/filter.d/
cp -f conf/fail2ban/jail.d/* /etc/fail2ban/jail.d/
# fail2ban should be able to look back far enough because we increased findtime of recidive jail
tools/editconf.py /etc/fail2ban/fail2ban.conf dbpurgeage=7d
# On first installation, the log files that the jails look at don't all exist.
# e.g., The roundcube error log isn't normally created until someone logs into

View File

@ -19,7 +19,7 @@ fi
echo "Installing Nginx (web server)..."
apt_install nginx php-cli php-fpm idn2
apt_install nginx php-cli php-fpm idn2 libnginx-mod-http-geoip
rm -f /etc/nginx/sites-enabled/default
@ -46,15 +46,21 @@ tools/editconf.py /etc/nginx/nginx.conf -s \
ssl_protocols="TLSv1.2 TLSv1.3;"
# Tell PHP not to expose its version number in the X-Powered-By header.
tools/editconf.py /etc/php/7.2/fpm/php.ini -c ';' \
tools/editconf.py /etc/php/$(php_version)/fpm/php.ini -c ';' \
expose_php=Off
# Set PHPs default charset to UTF-8, since we use it. See #367.
tools/editconf.py /etc/php/7.2/fpm/php.ini -c ';' \
tools/editconf.py /etc/php/$(php_version)/fpm/php.ini -c ';' \
default_charset="UTF-8"
# Set higher timeout since searches with Roundcube and Solr may take longer
# than the default 60 seconds. We will also match Roundcube's timeout to the
# same value
tools/editconf.py /etc/php/$(php_version)/fpm/php.ini -c ';' \
default_socket_timeout=180
# Configure the path environment for php-fpm
tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \
tools/editconf.py /etc/php/$(php_version)/fpm/pool.d/www.conf -c ';' \
env[PATH]=/usr/local/bin:/usr/bin:/bin \
# Configure php-fpm based on the amount of memory the machine has
@ -64,7 +70,7 @@ tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \
TOTAL_PHYSICAL_MEM=$(head -n 1 /proc/meminfo | awk '{print $2}' || /bin/true)
if [ $TOTAL_PHYSICAL_MEM -lt 1000000 ]
then
tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \
tools/editconf.py /etc/php/$(php_version)/fpm/pool.d/www.conf -c ';' \
pm=ondemand \
pm.max_children=8 \
pm.start_servers=2 \
@ -72,7 +78,7 @@ then
pm.max_spare_servers=3
elif [ $TOTAL_PHYSICAL_MEM -lt 2000000 ]
then
tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \
tools/editconf.py /etc/php/$(php_version)/fpm/pool.d/www.conf -c ';' \
pm=ondemand \
pm.max_children=16 \
pm.start_servers=4 \
@ -80,14 +86,14 @@ then
pm.max_spare_servers=6
elif [ $TOTAL_PHYSICAL_MEM -lt 3000000 ]
then
tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \
tools/editconf.py /etc/php/$(php_version)/fpm/pool.d/www.conf -c ';' \
pm=dynamic \
pm.max_children=60 \
pm.start_servers=6 \
pm.min_spare_servers=3 \
pm.max_spare_servers=9
else
tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \
tools/editconf.py /etc/php/$(php_version)/fpm/pool.d/www.conf -c ';' \
pm=dynamic \
pm.max_children=120 \
pm.start_servers=12 \
@ -145,9 +151,18 @@ if [ ! -f $STORAGE_ROOT/www/default/index.html ]; then
fi
chown -R $STORAGE_USER $STORAGE_ROOT/www
# Copy geoblock config file, but only if it does not exist to keep user config
if [ ! -f /etc/nginx/conf.d/10-geoblock.conf ]; then
cp -f conf/nginx/conf.d/10-geoblock.conf /etc/nginx/conf.d/
fi
# touch logfiles that might not exist
touch /var/log/nginx/geoipblock.log
chown www-data /var/log/nginx/geoipblock.log
# Start services.
restart_service nginx
restart_service php7.2-fpm
restart_service php$(php_version)-fpm
# Open ports.
ufw_allow http

View File

@ -33,8 +33,9 @@ VERSION=1.4.11
HASH=3877f0e70f29e7d0612155632e48c3db1e626be3
PERSISTENT_LOGIN_VERSION=6b3fc450cae23ccb2f393d0ef67aa319e877e435 # version 5.2.0
HTML5_NOTIFIER_VERSION=68d9ca194212e15b3c7225eb6085dbcf02fd13d7 # version 0.6.4+
CARDDAV_VERSION=3.0.3
CARDDAV_HASH=d1e3b0d851ffa2c6bd42bf0c04f70d0e1d0d78f8
CARDDAV_VERSION=4.1.1
CARDDAV_HASH=87b73661b7799b2079c28324311eddb4241242bb
UPDATE_KEY=$VERSION:$PERSISTENT_LOGIN_VERSION:$HTML5_NOTIFIER_VERSION:$CARDDAV_VERSION
@ -77,13 +78,14 @@ if [ $needs_update == 1 ]; then
# download and verify the full release of the carddav plugin
wget_verify \
https://github.com/blind-coder/rcmcarddav/releases/download/v${CARDDAV_VERSION}/carddav-${CARDDAV_VERSION}.zip \
https://github.com/mstilkerich/rcmcarddav/releases/download/v${CARDDAV_VERSION}/carddav-v${CARDDAV_VERSION}.tar.gz \
$CARDDAV_HASH \
/tmp/carddav.zip
/tmp/carddav.tar.gz
# unzip and cleanup
unzip -q /tmp/carddav.zip -d ${RCM_PLUGIN_DIR}
rm -f /tmp/carddav.zip
# unzip -q /tmp/carddav.tar.gz -d ${RCM_PLUGIN_DIR}
tar -C ${RCM_PLUGIN_DIR} --no-same-owner -zxf /tmp/carddav.tar.gz
rm -f /tmp/carddav.tar.gz
# record the version we've installed
echo $UPDATE_KEY > ${RCM_DIR}/version
@ -116,7 +118,7 @@ cat > $RCM_CONFIG <<EOF;
'verify_peer_name' => false,
),
);
\$config['imap_timeout'] = 15;
\$config['imap_timeout'] = 180;
\$config['smtp_server'] = 'tls://127.0.0.1';
\$config['smtp_conn_options'] = array(
'ssl' => array(
@ -199,4 +201,4 @@ chmod 664 $STORAGE_ROOT/mail/roundcube/roundcube.sqlite
# Enable PHP modules.
phpenmod -v php mcrypt imap
restart_service php7.2-fpm
restart_service php$(php_version)-fpm

BIN
tools/goiplookup.gz Normal file

Binary file not shown.

View File

@ -26,7 +26,7 @@ if [ ! -f $1/config.php ]; then
fi
echo "Restoring backup from $1"
service php7.2-fpm stop
service php7.3-fpm stop
# remove the current ownCloud/Nextcloud installation
rm -rf /usr/local/lib/owncloud/
@ -45,5 +45,5 @@ chown www-data.www-data $STORAGE_ROOT/owncloud/config.php
sudo -u www-data php /usr/local/lib/owncloud/occ maintenance:mode --off
service php7.2-fpm start
service php7.3-fpm start
echo "Done"

View File

@ -8,7 +8,7 @@
source /etc/mailinabox.conf # load global vars
ADMIN=$(./mail.py user admins | head -n 1)
ADMIN=$(./management/cli.py user admins | head -n 1)
test -z "$1" || ADMIN=$1
echo I am going to unlock admin features for $ADMIN.