mirror of
https://github.com/mail-in-a-box/mailinabox.git
synced 2024-12-25 07:47:05 +00:00
Merge remote-tracking branch 'origin/20.04'
This commit is contained in:
commit
a7955b39dd
@ -1,8 +1,8 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
In Development
|
v0.53 (April 12, 2021)
|
||||||
--------------
|
----------------------
|
||||||
|
|
||||||
Software updates:
|
Software updates:
|
||||||
|
|
||||||
|
13
README.md
13
README.md
@ -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
|
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
|
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."
|
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
|
$ git clone https://github.com/mail-in-a-box/mailinabox
|
||||||
$ cd mailinabox
|
$ cd mailinabox
|
||||||
$ git checkout v0.52
|
$ git checkout v0.53
|
||||||
|
|
||||||
Begin the installation.
|
Begin the installation.
|
||||||
|
|
||||||
|
5
conf/cron/miab_clean_mail
Normal file
5
conf/cron/miab_clean_mail
Normal 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
2
conf/cron/miab_dovecot
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
/usr/bin/doveadm fts rescan -A > /dev/null 2>&1
|
2
conf/cron/miab_solr
Normal file
2
conf/cron/miab_solr
Normal 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
|
24
conf/fail2ban/filter.d/nginx-badbots.conf
Normal file
24
conf/fail2ban/filter.d/nginx-badbots.conf
Normal 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
|
12
conf/fail2ban/filter.d/nginx-geoipblock.conf
Normal file
12
conf/fail2ban/filter.d/nginx-geoipblock.conf
Normal 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 =
|
10
conf/fail2ban/filter.d/ssh-geoipblock.conf
Normal file
10
conf/fail2ban/filter.d/ssh-geoipblock.conf
Normal 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 =
|
237
conf/fail2ban/filter.d/webexploits.conf
Normal file
237
conf/fail2ban/filter.d/webexploits.conf
Normal 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 =
|
17
conf/fail2ban/jail.d/geoipblock.conf
Normal file
17
conf/fail2ban/jail.d/geoipblock.conf
Normal 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
|
9
conf/fail2ban/jail.d/nginx-general.conf
Normal file
9
conf/fail2ban/jail.d/nginx-general.conf
Normal 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
|
8
conf/fail2ban/jail.d/webexploits.conf
Normal file
8
conf/fail2ban/jail.d/webexploits.conf
Normal 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
|
@ -5,13 +5,16 @@
|
|||||||
# Whitelist our own IP addresses. 127.0.0.1/8 is the default. But our status checks
|
# 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
|
# ping services over the public interface so we should whitelist that address of
|
||||||
# ours too. The string is substituted during installation.
|
# 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]
|
[dovecot]
|
||||||
enabled = true
|
enabled = true
|
||||||
filter = dovecotimap
|
filter = dovecotimap
|
||||||
logpath = /var/log/mail.log
|
logpath = /var/log/mail.log
|
||||||
findtime = 30
|
findtime = 2m
|
||||||
maxretry = 20
|
maxretry = 20
|
||||||
|
|
||||||
[miab-management]
|
[miab-management]
|
||||||
@ -20,7 +23,7 @@ filter = miab-management-daemon
|
|||||||
port = http,https
|
port = http,https
|
||||||
logpath = /var/log/syslog
|
logpath = /var/log/syslog
|
||||||
maxretry = 20
|
maxretry = 20
|
||||||
findtime = 30
|
findtime = 15m
|
||||||
|
|
||||||
[miab-munin]
|
[miab-munin]
|
||||||
enabled = true
|
enabled = true
|
||||||
@ -28,7 +31,7 @@ port = http,https
|
|||||||
filter = miab-munin
|
filter = miab-munin
|
||||||
logpath = /var/log/nginx/access.log
|
logpath = /var/log/nginx/access.log
|
||||||
maxretry = 20
|
maxretry = 20
|
||||||
findtime = 30
|
findtime = 15m
|
||||||
|
|
||||||
[miab-owncloud]
|
[miab-owncloud]
|
||||||
enabled = true
|
enabled = true
|
||||||
@ -36,7 +39,7 @@ port = http,https
|
|||||||
filter = miab-owncloud
|
filter = miab-owncloud
|
||||||
logpath = STORAGE_ROOT/owncloud/nextcloud.log
|
logpath = STORAGE_ROOT/owncloud/nextcloud.log
|
||||||
maxretry = 20
|
maxretry = 20
|
||||||
findtime = 120
|
findtime = 15m
|
||||||
|
|
||||||
[miab-postfix587]
|
[miab-postfix587]
|
||||||
enabled = true
|
enabled = true
|
||||||
@ -44,7 +47,7 @@ port = 587
|
|||||||
filter = miab-postfix-submission
|
filter = miab-postfix-submission
|
||||||
logpath = /var/log/mail.log
|
logpath = /var/log/mail.log
|
||||||
maxretry = 20
|
maxretry = 20
|
||||||
findtime = 30
|
findtime = 2m
|
||||||
|
|
||||||
[miab-roundcube]
|
[miab-roundcube]
|
||||||
enabled = true
|
enabled = true
|
||||||
@ -52,11 +55,13 @@ port = http,https
|
|||||||
filter = miab-roundcube
|
filter = miab-roundcube
|
||||||
logpath = /var/log/roundcubemail/errors.log
|
logpath = /var/log/roundcubemail/errors.log
|
||||||
maxretry = 20
|
maxretry = 20
|
||||||
findtime = 30
|
findtime = 15m
|
||||||
|
|
||||||
[recidive]
|
[recidive]
|
||||||
enabled = true
|
enabled = true
|
||||||
maxretry = 10
|
maxretry = 10
|
||||||
|
bantime = 2w
|
||||||
|
findtime = 3d
|
||||||
action = iptables-allports[name=recidive]
|
action = iptables-allports[name=recidive]
|
||||||
# In the recidive section of jail.conf the action contains:
|
# In the recidive section of jail.conf the action contains:
|
||||||
#
|
#
|
||||||
@ -71,8 +76,17 @@ action = iptables-allports[name=recidive]
|
|||||||
|
|
||||||
[postfix-sasl]
|
[postfix-sasl]
|
||||||
enabled = true
|
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]
|
[sshd]
|
||||||
enabled = true
|
enabled = true
|
||||||
maxretry = 7
|
maxretry = 4
|
||||||
bantime = 3600
|
bantime = 3600
|
||||||
|
mode = aggressive
|
||||||
|
3
conf/geoiplookup.conf
Normal file
3
conf/geoiplookup.conf
Normal 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=""
|
@ -49,26 +49,6 @@
|
|||||||
client_max_body_size 128M;
|
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
|
# ADDITIONAL DIRECTIVES HERE
|
||||||
|
|
||||||
# Disable viewing dotfiles (.htaccess, .svn, .git, etc.)
|
# Disable viewing dotfiles (.htaccess, .svn, .git, etc.)
|
||||||
|
@ -7,6 +7,30 @@
|
|||||||
rewrite ^/admin$ /admin/;
|
rewrite ^/admin$ /admin/;
|
||||||
rewrite ^/admin/munin$ /admin/munin/ redirect;
|
rewrite ^/admin/munin$ /admin/munin/ redirect;
|
||||||
location /admin/ {
|
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_pass http://127.0.0.1:10222/;
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
add_header X-Frame-Options "DENY";
|
add_header X-Frame-Options "DENY";
|
||||||
|
@ -7,6 +7,5 @@
|
|||||||
## your own --- please do not ask for help from us.
|
## your own --- please do not ask for help from us.
|
||||||
|
|
||||||
upstream php-fpm {
|
upstream php-fpm {
|
||||||
server unix:/var/run/php/php7.2-fpm.sock;
|
server unix:/var/run/php/php{{phpver}}-fpm.sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
conf/nginx-webonlydomains.conf
Normal file
28
conf/nginx-webonlydomains.conf
Normal 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;
|
||||||
|
}
|
22
conf/nginx/conf.d/10-geoblock.conf
Normal file
22
conf/nginx/conf.d/10-geoblock.conf
Normal 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';
|
289
conf/solr/solr-config-7.7.0.xml
Normal file
289
conf/solr/solr-config-7.7.0.xml
Normal 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
22
conf/solr/solr-jetty.xml
Normal 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>
|
48
conf/solr/solr-schema-7.7.0.xml
Normal file
48
conf/solr/solr-schema-7.7.0.xml
Normal 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
20
conf/solr/solr.service
Normal 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
|
@ -12,7 +12,7 @@ import dateutil.parser, dateutil.relativedelta, dateutil.tz
|
|||||||
import rtyaml
|
import rtyaml
|
||||||
from exclusiveprocess import Lock
|
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 = [
|
rsync_ssh_options = [
|
||||||
"--ssh-options= -i /root/.ssh/id_rsa_miab",
|
"--ssh-options= -i /root/.ssh/id_rsa_miab",
|
||||||
@ -20,7 +20,7 @@ rsync_ssh_options = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
def backup_status(env):
|
def backup_status(env):
|
||||||
# If backups are dissbled, return no status.
|
# If backups are disabled, return no status.
|
||||||
config = get_backup_config(env)
|
config = get_backup_config(env)
|
||||||
if config["target"] == "off":
|
if config["target"] == "off":
|
||||||
return { }
|
return { }
|
||||||
@ -212,9 +212,10 @@ def get_target_type(config):
|
|||||||
|
|
||||||
def perform_backup(full_backup):
|
def perform_backup(full_backup):
|
||||||
env = load_environment()
|
env = load_environment()
|
||||||
|
php_fpm = f"php{get_php_version()}-fpm"
|
||||||
|
|
||||||
# Create an global exclusive lock so that the backup script
|
# 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()
|
Lock(die=True).forever()
|
||||||
|
|
||||||
config = get_backup_config(env)
|
config = get_backup_config(env)
|
||||||
@ -247,7 +248,7 @@ def perform_backup(full_backup):
|
|||||||
if quit:
|
if quit:
|
||||||
sys.exit(code)
|
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("postfix", "stop", quit=True)
|
||||||
service_command("dovecot", "stop", quit=True)
|
service_command("dovecot", "stop", quit=True)
|
||||||
|
|
||||||
@ -281,7 +282,7 @@ def perform_backup(full_backup):
|
|||||||
# Start services again.
|
# Start services again.
|
||||||
service_command("dovecot", "start", quit=False)
|
service_command("dovecot", "start", quit=False)
|
||||||
service_command("postfix", "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
|
# Remove old backups. This deletes all backup data no longer needed
|
||||||
# from more than 3 days ago.
|
# from more than 3 days ago.
|
||||||
@ -316,6 +317,13 @@ def perform_backup(full_backup):
|
|||||||
if get_target_type(config) == 'file':
|
if get_target_type(config) == 'file':
|
||||||
shell('check_call', ["/bin/chown", "-R", env["STORAGE_USER"], backup_dir])
|
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.
|
# 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
|
# Run as the STORAGE_USER user, not as root. Pass our settings in
|
||||||
# environment variables so the script has access to STORAGE_ROOT.
|
# 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"]],
|
['su', env['STORAGE_USER'], '-c', post_script, config["target"]],
|
||||||
env=env)
|
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():
|
def run_duplicity_verification():
|
||||||
env = load_environment()
|
env = load_environment()
|
||||||
backup_root = os.path.join(env["STORAGE_ROOT"], 'backup')
|
backup_root = os.path.join(env["STORAGE_ROOT"], 'backup')
|
||||||
|
@ -512,7 +512,10 @@ def web_get_domains():
|
|||||||
@authorized_personnel_only
|
@authorized_personnel_only
|
||||||
def web_update():
|
def web_update():
|
||||||
from web_update import do_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
|
# System
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ export LC_TYPE=en_US.UTF-8
|
|||||||
# sent and received so the admin might notice server abuse.
|
# sent and received so the admin might notice server abuse.
|
||||||
if [ `date "+%u"` -eq 1 ]; then
|
if [ `date "+%u"` -eq 1 ]; then
|
||||||
management/mail_log.py -t week | management/email_administrator.py "Mail-in-a-Box Usage Report"
|
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
|
fi
|
||||||
|
|
||||||
# Take a backup.
|
# Take a backup.
|
||||||
|
@ -949,9 +949,9 @@ def get_secondary_dns(custom_dns, mode=None):
|
|||||||
# doesn't.
|
# doesn't.
|
||||||
if not hostname.startswith("xfr:"):
|
if not hostname.startswith("xfr:"):
|
||||||
if mode == "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))
|
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))
|
values.extend(map(str, response))
|
||||||
continue
|
continue
|
||||||
values.append(hostname)
|
values.append(hostname)
|
||||||
@ -974,7 +974,7 @@ def set_secondary_dns(hostnames, env):
|
|||||||
if not item.startswith("xfr:"):
|
if not item.startswith("xfr:"):
|
||||||
# Resolve hostname.
|
# Resolve hostname.
|
||||||
try:
|
try:
|
||||||
response = resolver.query(item, "A")
|
response = resolver.resolve(item, "A")
|
||||||
except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
||||||
try:
|
try:
|
||||||
response = resolver.query(item, "AAAA")
|
response = resolver.query(item, "AAAA")
|
||||||
|
@ -525,6 +525,9 @@ def get_required_aliases(env):
|
|||||||
# The hostmaster alias is exposed in the DNS SOA for each zone.
|
# The hostmaster alias is exposed in the DNS SOA for each zone.
|
||||||
aliases.add("hostmaster@" + env['PRIMARY_HOSTNAME'])
|
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
|
# 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.
|
# email on that domain are the required aliases or a catch-all/domain-forwarder.
|
||||||
real_mail_domains = get_mail_domains(env,
|
real_mail_domains = get_mail_domains(env,
|
||||||
|
@ -110,6 +110,14 @@ def validate_auth_mfa(email, request, env):
|
|||||||
if len(mfa_state) == 0:
|
if len(mfa_state) == 0:
|
||||||
return (True, [])
|
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.
|
# Try the enabled MFA modes.
|
||||||
hints = set()
|
hints = set()
|
||||||
for mfa_mode in mfa_state:
|
for mfa_mode in mfa_state:
|
||||||
|
@ -346,6 +346,8 @@ def provision_certificates(env, limit_domains):
|
|||||||
"certonly",
|
"certonly",
|
||||||
#"-v", # just enough to see ACME errors
|
#"-v", # just enough to see ACME errors
|
||||||
"--non-interactive", # will fail if user hasn't registered during Mail-in-a-Box setup
|
"--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
|
"-d", ",".join(domain_list), # first will be main domain
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ def get_services():
|
|||||||
{ "name": "Mail Filters (Sieve/dovecot)", "port": 4190, "public": True, },
|
{ "name": "Mail Filters (Sieve/dovecot)", "port": 4190, "public": True, },
|
||||||
{ "name": "HTTP Web (nginx)", "port": 80, "public": True, },
|
{ "name": "HTTP Web (nginx)", "port": 80, "public": True, },
|
||||||
{ "name": "HTTPS Web (nginx)", "port": 443, "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):
|
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.
|
# Do the query.
|
||||||
try:
|
try:
|
||||||
response = resolver.query(qname, rtype)
|
response = resolver.resolve(qname, rtype)
|
||||||
except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
||||||
# Host did not have an answer for this query; not sure what the
|
# Host did not have an answer for this query; not sure what the
|
||||||
# difference is between the two exceptions.
|
# 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,
|
# 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.
|
# so this function may raise all sorts of exceptions.
|
||||||
miab_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
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
|
return tag
|
||||||
|
|
||||||
def get_latest_miab_version():
|
def get_latest_miab_version():
|
||||||
@ -857,16 +858,16 @@ def check_miab_version(env, output):
|
|||||||
this_ver = "Unknown"
|
this_ver = "Unknown"
|
||||||
|
|
||||||
if config.get("privacy", True):
|
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:
|
else:
|
||||||
latest_ver = get_latest_miab_version()
|
latest_ver = get_latest_miab_version()
|
||||||
|
|
||||||
if this_ver == latest_ver:
|
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:
|
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:
|
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))
|
% (this_ver, latest_ver))
|
||||||
|
|
||||||
def run_and_output_changes(env, pool):
|
def run_and_output_changes(env, pool):
|
||||||
|
@ -182,6 +182,9 @@ def fix_boto():
|
|||||||
import os
|
import os
|
||||||
os.environ["BOTO_CONFIG"] = "/etc/boto3.cfg"
|
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__":
|
if __name__ == "__main__":
|
||||||
from web_update import get_web_domains
|
from web_update import get_web_domains
|
||||||
|
@ -7,7 +7,8 @@ import os.path, re, rtyaml
|
|||||||
from mailconfig import get_mail_domains
|
from mailconfig import get_mail_domains
|
||||||
from dns_update import get_custom_dns_config, get_dns_zones
|
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 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):
|
def get_web_domains(env, include_www_redirects=True, exclude_dns_elsewhere=True):
|
||||||
# What domains should we serve HTTP(S) for?
|
# 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.
|
# if the user wants to make one.
|
||||||
domains |= get_mail_domains(env)
|
domains |= get_mail_domains(env)
|
||||||
|
|
||||||
|
# Add domains for which we only serve www
|
||||||
|
domains |= get_www_domains(domains)
|
||||||
|
|
||||||
if include_www_redirects:
|
if include_www_redirects:
|
||||||
# Add 'www.' subdomains that we want to provide default 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.
|
# to the main domain for. We'll add 'www.' to any DNS zones, i.e.
|
||||||
# the topmost of each domain we serve.
|
# the topmost of each domain we serve.
|
||||||
domains |= set('www.' + zone for zone, zonefile in get_dns_zones(env))
|
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:
|
# Add Autoconfiguration domains for domains that there are user accounts at:
|
||||||
# 'autoconfig.' for Mozilla Thunderbird auto setup.
|
# 'autoconfig.' for Mozilla Thunderbird auto setup.
|
||||||
@ -76,12 +81,14 @@ def do_web_update(env):
|
|||||||
|
|
||||||
# Build an nginx configuration file.
|
# Build an nginx configuration file.
|
||||||
nginx_conf = open(os.path.join(os.path.dirname(__file__), "../conf/nginx-top.conf")).read()
|
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.
|
# Load the templates.
|
||||||
template0 = open(os.path.join(os.path.dirname(__file__), "../conf/nginx.conf")).read()
|
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()
|
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()
|
template2 = open(os.path.join(os.path.dirname(__file__), "../conf/nginx-primaryonly.conf")).read()
|
||||||
template3 = "\trewrite ^(.*) https://$REDIRECT_DOMAIN$1 permanent;\n"
|
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.
|
# 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)
|
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.
|
# Add configuration all other web domains.
|
||||||
has_root_proxy_or_redirect = get_web_domains_with_root_overrides(env)
|
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_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):
|
for domain in get_web_domains(env):
|
||||||
if domain == env['PRIMARY_HOSTNAME']:
|
if domain == env['PRIMARY_HOSTNAME']:
|
||||||
# PRIMARY_HOSTNAME is handled above.
|
# PRIMARY_HOSTNAME is handled above.
|
||||||
@ -96,7 +105,10 @@ def do_web_update(env):
|
|||||||
if domain in web_domains_not_redirect:
|
if domain in web_domains_not_redirect:
|
||||||
# This is a regular domain.
|
# This is a regular domain.
|
||||||
if domain not in has_root_proxy_or_redirect:
|
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:
|
else:
|
||||||
nginx_conf += make_domain_config(domain, [template0], ssl_certificates, env)
|
nginx_conf += make_domain_config(domain, [template0], ssl_certificates, env)
|
||||||
else:
|
else:
|
||||||
@ -221,6 +233,10 @@ def get_web_root(domain, env, test_exists=True):
|
|||||||
if os.path.exists(root) or not test_exists: break
|
if os.path.exists(root) or not test_exists: break
|
||||||
return root
|
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):
|
def get_web_domains_info(env):
|
||||||
www_redirects = set(get_web_domains(env)) - set(get_web_domains(env, include_www_redirects=False))
|
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))
|
has_root_proxy_or_redirect = set(get_web_domains_with_root_overrides(env))
|
||||||
|
34
management/wwwconfig.py
Normal file
34
management/wwwconfig.py
Normal 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
27
setup/additionals.sh
Normal 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
|
@ -18,9 +18,13 @@ if [ -z "$TAG" ]; then
|
|||||||
# space, but if we put it in a comment it would confuse the status checks!)
|
# 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
|
# to get the latest version, so the first such line must be the one that we
|
||||||
# want to display in status checks.
|
# 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.
|
# 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
|
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.
|
# This machine is running Ubuntu 14.04.
|
||||||
@ -34,7 +38,7 @@ if [ -z "$TAG" ]; then
|
|||||||
TAG=v0.30
|
TAG=v0.30
|
||||||
|
|
||||||
else
|
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
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@ -68,7 +72,7 @@ fi
|
|||||||
cd $HOME/mailinabox
|
cd $HOME/mailinabox
|
||||||
|
|
||||||
# Update it.
|
# Update it.
|
||||||
if [ "$TAG" != `git describe` ]; then
|
if [ "$TAG" != "`git describe --tags`" ]; then
|
||||||
echo Updating Mail-in-a-Box to $TAG . . .
|
echo Updating Mail-in-a-Box to $TAG . . .
|
||||||
git fetch --depth 1 --force --prune origin tag $TAG
|
git fetch --depth 1 --force --prune origin tag $TAG
|
||||||
if ! git checkout -q $TAG; then
|
if ! git checkout -q $TAG; then
|
||||||
|
17
setup/dns.sh
17
setup/dns.sh
@ -16,11 +16,15 @@ source /etc/mailinabox.conf # load global vars
|
|||||||
# * ldnsutils: Helper utilities for signing DNSSEC zones.
|
# * ldnsutils: Helper utilities for signing DNSSEC zones.
|
||||||
# * openssh-client: Provides ssh-keyscan which we use to create SSHFP records.
|
# * openssh-client: Provides ssh-keyscan which we use to create SSHFP records.
|
||||||
echo "Installing nsd (DNS server)..."
|
echo "Installing nsd (DNS server)..."
|
||||||
apt_install nsd ldnsutils openssh-client
|
apt_install ldnsutils openssh-client
|
||||||
|
|
||||||
# Prepare nsd's configuration.
|
# Prepare nsd's configuration.
|
||||||
|
|
||||||
mkdir -p /var/run/nsd
|
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;
|
cat > /etc/nsd/nsd.conf << EOF;
|
||||||
# Do not edit. Overwritten by Mail-in-a-Box setup.
|
# 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;
|
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.
|
# Create DNSSEC signing keys.
|
||||||
|
|
||||||
mkdir -p "$STORAGE_ROOT/dns/dnssec";
|
mkdir -p "$STORAGE_ROOT/dns/dnssec";
|
||||||
|
@ -221,3 +221,7 @@ function git_clone {
|
|||||||
mv $TMPPATH/$SUBDIR $TARGETPATH
|
mv $TMPPATH/$SUBDIR $TARGETPATH
|
||||||
rm -rf $TMPPATH
|
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
41
setup/geoipfilter.sh
Normal 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
104
setup/geoiptoolssetup.sh
Normal 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
|
||||||
|
|
@ -137,6 +137,14 @@ tools/editconf.py /etc/postfix/main.cf \
|
|||||||
tls_preempt_cipherlist=no \
|
tls_preempt_cipherlist=no \
|
||||||
smtpd_tls_received_header=yes
|
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
|
# Prevent non-authenticated users from sending mail that requires being
|
||||||
# relayed elsewhere. We don't want to be an "open relay". On outbound
|
# relayed elsewhere. We don't want to be an "open relay". On outbound
|
||||||
# mail, require one of:
|
# 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_sasl_authenticated`: Authenticated users (i.e. on port 587).
|
||||||
# * `permit_mynetworks`: Mail that originates locally.
|
# * `permit_mynetworks`: Mail that originates locally.
|
||||||
# * `reject_unauth_destination`: No one else. (Permits mail whose destination is local and rejects other mail.)
|
# * `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 \
|
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
|
# ### DANE
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ done
|
|||||||
#
|
#
|
||||||
# certbot installs EFF's certbot which we use to
|
# certbot installs EFF's certbot which we use to
|
||||||
# provision free TLS certificates.
|
# provision free TLS certificates.
|
||||||
apt_install duplicity python-pip virtualenv certbot
|
apt_install duplicity python3-pip virtualenv certbot
|
||||||
|
|
||||||
# b2sdk is used for backblaze backups.
|
# b2sdk is used for backblaze backups.
|
||||||
# boto is used for amazon aws backups.
|
# boto is used for amazon aws backups.
|
||||||
|
@ -23,14 +23,15 @@ includedir /etc/munin/munin-conf.d
|
|||||||
# path dynazoom uses for requests
|
# path dynazoom uses for requests
|
||||||
cgiurl_graph /admin/munin/cgi-graph
|
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
|
# a simple host tree
|
||||||
[$PRIMARY_HOSTNAME]
|
[$PRIMARY_HOSTNAME]
|
||||||
address 127.0.0.1
|
address 127.0.0.1
|
||||||
|
|
||||||
# send alerts to the following address
|
|
||||||
contacts admin
|
contacts admin
|
||||||
contact.admin.command mail -s "Munin notification \${var:host}" administrator@$PRIMARY_HOSTNAME
|
|
||||||
contact.admin.always_send warning critical
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# The Debian installer touches these files and chowns them to www-data:adm for use with spawn-fcgi
|
# 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 unmask munin.service
|
||||||
hide_output systemctl enable 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 services.
|
||||||
restart_service munin
|
restart_service munin
|
||||||
restart_service munin-node
|
restart_service munin-node
|
||||||
|
@ -42,6 +42,9 @@ InstallNextcloud() {
|
|||||||
mv /usr/local/lib/nextcloud /usr/local/lib/owncloud
|
mv /usr/local/lib/nextcloud /usr/local/lib/owncloud
|
||||||
rm -f /tmp/nextcloud.zip
|
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
|
# The two apps we actually want are not in Nextcloud core. Download the releases from
|
||||||
# their github repositories.
|
# their github repositories.
|
||||||
mkdir -p /usr/local/lib/owncloud/apps
|
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 Version to install. Checks are done down below to step through intermediate versions.
|
||||||
nextcloud_ver=20.0.1
|
nextcloud_ver=20.0.8
|
||||||
nextcloud_hash=f2b3faa570c541df73f209e873a1c2852e79eab8
|
nextcloud_hash=372b0b4bb07c7984c04917aff86b280e68fbe761
|
||||||
contacts_ver=3.4.1
|
contacts_ver=3.5.1
|
||||||
contacts_hash=aee680a75e95f26d9285efd3c1e25cf7f3bfd27e
|
contacts_hash=d2ffbccd3ed89fa41da20a1dff149504c3b33b93
|
||||||
calendar_ver=2.1.2
|
calendar_ver=2.1.3
|
||||||
calendar_hash=930c07863bb7a65652dec34793802c8d80502336
|
calendar_hash=d7d9db0e55ff1c9c2a2356e8980a8d9fce3fc4a0
|
||||||
user_external_ver=1.0.0
|
user_external_ver=1.0.0
|
||||||
user_external_hash=3bf2609061d7214e7f0f69dd8883e55c4ec8f50a
|
user_external_hash=3bf2609061d7214e7f0f69dd8883e55c4ec8f50a
|
||||||
|
|
||||||
@ -124,7 +127,7 @@ fi
|
|||||||
if [ ! -d /usr/local/lib/owncloud/ ] || [[ ! ${CURRENT_NEXTCLOUD_VER} =~ ^$nextcloud_ver ]]; then
|
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.
|
# 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.
|
# Backup the existing ownCloud/Nextcloud.
|
||||||
# Create a backup directory to store the current installation and database to
|
# 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
|
# Set PHP FPM values to support large file uploads
|
||||||
# (semicolon is the comment character in this file, hashes produce deprecation warnings)
|
# (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 \
|
upload_max_filesize=16G \
|
||||||
post_max_size=16G \
|
post_max_size=16G \
|
||||||
output_buffering=16384 \
|
output_buffering=16384 \
|
||||||
@ -325,7 +328,7 @@ tools/editconf.py /etc/php/7.2/fpm/php.ini -c ';' \
|
|||||||
short_open_tag=On
|
short_open_tag=On
|
||||||
|
|
||||||
# Set Nextcloud recommended opcache settings
|
# 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=1 \
|
||||||
opcache.enable_cli=1 \
|
opcache.enable_cli=1 \
|
||||||
opcache.interned_strings_buffer=8 \
|
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
|
opcache.revalidate_freq=1
|
||||||
|
|
||||||
# If apc is explicitly disabled we need to enable it
|
# 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
|
if grep -q apc.enabled=0 /etc/php/$(php_version)/mods-available/apcu.ini; then
|
||||||
tools/editconf.py /etc/php/7.2/mods-available/apcu.ini -c ';' \
|
tools/editconf.py /etc/php/$(php_version)/mods-available/apcu.ini -c ';' \
|
||||||
apc.enabled=1
|
apc.enabled=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -361,4 +364,4 @@ rm -f /etc/cron.hourly/mailinabox-owncloud
|
|||||||
# ```
|
# ```
|
||||||
|
|
||||||
# Enable PHP modules and restart PHP.
|
# Enable PHP modules and restart PHP.
|
||||||
restart_service php7.2-fpm
|
restart_service php$(php_version)-fpm
|
||||||
|
@ -7,9 +7,10 @@ if [[ $EUID -ne 0 ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check that we are running on Ubuntu 18.04 LTS (or 18.04.xx).
|
# Check that we are running on Debian GNU/Linux, or Ubuntu 20.04
|
||||||
if [ "`lsb_release -d | sed 's/.*:\s*//' | sed 's/18\.04\.[0-9]/18.04/' `" != "Ubuntu 18.04 LTS" ]; then
|
OS=`lsb_release -d | sed 's/.*:\s*//'`
|
||||||
echo "Mail-in-a-Box only supports being installed on Ubuntu 18.04, sorry. You are running:"
|
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
|
echo
|
||||||
lsb_release -d | sed 's/.*:\s*//'
|
lsb_release -d | sed 's/.*:\s*//'
|
||||||
echo
|
echo
|
||||||
|
@ -9,7 +9,7 @@ if [ -z "${NONINTERACTIVE:-}" ]; then
|
|||||||
if [ ! -f /usr/bin/dialog ] || [ ! -f /usr/bin/python3 ] || [ ! -f /usr/bin/pip3 ]; then
|
if [ ! -f /usr/bin/dialog ] || [ ! -f /usr/bin/python3 ] || [ ! -f /usr/bin/pip3 ]; then
|
||||||
echo Installing packages needed for setup...
|
echo Installing packages needed for setup...
|
||||||
apt-get -q -q update
|
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
|
fi
|
||||||
|
|
||||||
# Installing email_validator is repeated in setup/management.sh, but in setup/management.sh
|
# 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
|
||||||
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
|
# Same for IPv6. But it's optional. Also, if it looks like the system
|
||||||
# doesn't have an IPv6, don't ask for one.
|
# doesn't have an IPv6, don't ask for one.
|
||||||
if [ -z "${PUBLIC_IPV6:-}" ]; then
|
if [ -z "${PUBLIC_IPV6:-}" ]; then
|
||||||
@ -206,7 +224,10 @@ fi
|
|||||||
if [ "$PRIVATE_IPV6" != "$PUBLIC_IPV6" ]; then
|
if [ "$PRIVATE_IPV6" != "$PUBLIC_IPV6" ]; then
|
||||||
echo "Private IPv6 Address: $PRIVATE_IPV6"
|
echo "Private IPv6 Address: $PRIVATE_IPV6"
|
||||||
fi
|
fi
|
||||||
|
if [ -n "$ADMIN_HOME_IP" ]; then
|
||||||
|
echo "Admin Home IP Address: $ADMIN_HOME_IP"
|
||||||
|
fi
|
||||||
if [ -f /usr/bin/git ] && [ -d .git ]; then
|
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
|
fi
|
||||||
echo
|
echo
|
||||||
|
166
setup/solr.sh
Normal file
166
setup/solr.sh
Normal 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 '*'
|
@ -195,3 +195,4 @@ chmod 770 $STORAGE_ROOT/mail/spamassassin
|
|||||||
restart_service spampd
|
restart_service spampd
|
||||||
restart_service dovecot
|
restart_service dovecot
|
||||||
|
|
||||||
|
systemctl enable spamassassin.service
|
@ -14,9 +14,14 @@ source setup/preflight.sh
|
|||||||
# Python may not be able to read/write files. This is also
|
# Python may not be able to read/write files. This is also
|
||||||
# in the management daemon startup script and the cron script.
|
# 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
|
if ! locale -a | grep en_US.utf8 > /dev/null; then
|
||||||
|
echo "Generating locales..."
|
||||||
# Generate locale if not exists
|
# 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
|
fi
|
||||||
|
|
||||||
export LANGUAGE=en_US.UTF-8
|
export LANGUAGE=en_US.UTF-8
|
||||||
@ -95,23 +100,27 @@ PUBLIC_IPV6=$PUBLIC_IPV6
|
|||||||
PRIVATE_IP=$PRIVATE_IP
|
PRIVATE_IP=$PRIVATE_IP
|
||||||
PRIVATE_IPV6=$PRIVATE_IPV6
|
PRIVATE_IPV6=$PRIVATE_IPV6
|
||||||
MTA_STS_MODE=${MTA_STS_MODE-}
|
MTA_STS_MODE=${MTA_STS_MODE-}
|
||||||
|
ADMIN_HOME_IP=$ADMIN_HOME_IP
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Start service configuration.
|
# Start service configuration.
|
||||||
source setup/system.sh
|
source setup/system.sh
|
||||||
|
source setup/geoiptoolssetup.sh
|
||||||
source setup/ssl.sh
|
source setup/ssl.sh
|
||||||
source setup/dns.sh
|
source setup/dns.sh
|
||||||
source setup/mail-postfix.sh
|
source setup/mail-postfix.sh
|
||||||
source setup/mail-dovecot.sh
|
source setup/mail-dovecot.sh
|
||||||
source setup/mail-users.sh
|
source setup/mail-users.sh
|
||||||
|
#source setup/solr.sh
|
||||||
source setup/dkim.sh
|
source setup/dkim.sh
|
||||||
source setup/spamassassin.sh
|
source setup/spamassassin.sh
|
||||||
source setup/web.sh
|
source setup/web.sh
|
||||||
source setup/webmail.sh
|
source setup/webmail.sh
|
||||||
source setup/nextcloud.sh
|
source setup/nextcloud.sh
|
||||||
source setup/zpush.sh
|
#source setup/zpush.sh
|
||||||
source setup/management.sh
|
source setup/management.sh
|
||||||
source setup/munin.sh
|
source setup/munin.sh
|
||||||
|
source setup/additionals.sh
|
||||||
|
|
||||||
# Wait for the management daemon to start...
|
# Wait for the management daemon to start...
|
||||||
until nc -z -w 4 127.0.0.1 10222
|
until nc -z -w 4 127.0.0.1 10222
|
||||||
|
@ -75,26 +75,7 @@ then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ### Add PPAs.
|
# Certbot doesn't require a PPA in Debian
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# ### Update Packages
|
# ### Update Packages
|
||||||
|
|
||||||
@ -258,20 +239,21 @@ if [ -z "${DISABLE_FIREWALL:-}" ]; then
|
|||||||
# Install `ufw` which provides a simple firewall configuration.
|
# Install `ufw` which provides a simple firewall configuration.
|
||||||
apt_install ufw
|
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
|
# 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
|
# settings, find the port it is supposedly running on, and open that port #NODOC
|
||||||
# too. #NODOC
|
# too. #NODOC
|
||||||
SSH_PORT=$(sshd -T 2>/dev/null | grep "^port " | sed "s/port //") #NODOC
|
SSH_PORT=$(sshd -T 2>/dev/null | grep "^port " | sed "s/port //") #NODOC
|
||||||
if [ ! -z "$SSH_PORT" ]; then
|
if [ ! -z "$SSH_PORT" ]; then
|
||||||
if [ "$SSH_PORT" != "22" ]; then
|
if [ "$SSH_PORT" != "22" ]; then
|
||||||
|
echo Opening alternate SSH port $SSH_PORT. #NODOC
|
||||||
echo Opening alternate SSH port $SSH_PORT. #NODOC
|
ufw_limit $SSH_PORT #NODOC
|
||||||
ufw_limit $SSH_PORT #NODOC
|
else
|
||||||
|
# Allow incoming connections to SSH.
|
||||||
fi
|
ufw_limit ssh;
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Allow incoming connections to SSH.
|
||||||
|
ufw_limit ssh;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ufw --force enable;
|
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,
|
# 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.
|
# we ran into the limit thus we are increasing it from 75 (default value) to 100.
|
||||||
apt_install bind9
|
apt_install bind9
|
||||||
|
touch /etc/default/bind9
|
||||||
tools/editconf.py /etc/default/bind9 \
|
tools/editconf.py /etc/default/bind9 \
|
||||||
"OPTIONS=\"-u bind -4\""
|
"OPTIONS=\"-u bind -4\""
|
||||||
if ! grep -q "listen-on " /etc/bind/named.conf.options; then
|
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.
|
# 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
|
sed -i "s/^}/\n\tlisten-on { 127.0.0.1; };\n}/" /etc/bind/named.conf.options
|
||||||
fi
|
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
|
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.
|
# 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
|
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
|
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 \
|
cat conf/fail2ban/jails.conf \
|
||||||
| sed "s/PUBLIC_IP/$PUBLIC_IP/g" \
|
| sed "s/PUBLIC_IP/$PUBLIC_IP/g" \
|
||||||
|
| sed "s/ADMIN_HOME_IP/$ADMIN_HOME_IP/g" \
|
||||||
| sed "s#STORAGE_ROOT#$STORAGE_ROOT#" \
|
| 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/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.
|
# 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
|
# e.g., The roundcube error log isn't normally created until someone logs into
|
||||||
|
33
setup/web.sh
33
setup/web.sh
@ -19,7 +19,7 @@ fi
|
|||||||
|
|
||||||
echo "Installing Nginx (web server)..."
|
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
|
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;"
|
ssl_protocols="TLSv1.2 TLSv1.3;"
|
||||||
|
|
||||||
# Tell PHP not to expose its version number in the X-Powered-By header.
|
# 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
|
expose_php=Off
|
||||||
|
|
||||||
# Set PHPs default charset to UTF-8, since we use it. See #367.
|
# 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"
|
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
|
# 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 \
|
env[PATH]=/usr/local/bin:/usr/bin:/bin \
|
||||||
|
|
||||||
# Configure php-fpm based on the amount of memory the machine has
|
# 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)
|
TOTAL_PHYSICAL_MEM=$(head -n 1 /proc/meminfo | awk '{print $2}' || /bin/true)
|
||||||
if [ $TOTAL_PHYSICAL_MEM -lt 1000000 ]
|
if [ $TOTAL_PHYSICAL_MEM -lt 1000000 ]
|
||||||
then
|
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=ondemand \
|
||||||
pm.max_children=8 \
|
pm.max_children=8 \
|
||||||
pm.start_servers=2 \
|
pm.start_servers=2 \
|
||||||
@ -72,7 +78,7 @@ then
|
|||||||
pm.max_spare_servers=3
|
pm.max_spare_servers=3
|
||||||
elif [ $TOTAL_PHYSICAL_MEM -lt 2000000 ]
|
elif [ $TOTAL_PHYSICAL_MEM -lt 2000000 ]
|
||||||
then
|
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=ondemand \
|
||||||
pm.max_children=16 \
|
pm.max_children=16 \
|
||||||
pm.start_servers=4 \
|
pm.start_servers=4 \
|
||||||
@ -80,14 +86,14 @@ then
|
|||||||
pm.max_spare_servers=6
|
pm.max_spare_servers=6
|
||||||
elif [ $TOTAL_PHYSICAL_MEM -lt 3000000 ]
|
elif [ $TOTAL_PHYSICAL_MEM -lt 3000000 ]
|
||||||
then
|
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=dynamic \
|
||||||
pm.max_children=60 \
|
pm.max_children=60 \
|
||||||
pm.start_servers=6 \
|
pm.start_servers=6 \
|
||||||
pm.min_spare_servers=3 \
|
pm.min_spare_servers=3 \
|
||||||
pm.max_spare_servers=9
|
pm.max_spare_servers=9
|
||||||
else
|
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=dynamic \
|
||||||
pm.max_children=120 \
|
pm.max_children=120 \
|
||||||
pm.start_servers=12 \
|
pm.start_servers=12 \
|
||||||
@ -145,9 +151,18 @@ if [ ! -f $STORAGE_ROOT/www/default/index.html ]; then
|
|||||||
fi
|
fi
|
||||||
chown -R $STORAGE_USER $STORAGE_ROOT/www
|
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.
|
# Start services.
|
||||||
restart_service nginx
|
restart_service nginx
|
||||||
restart_service php7.2-fpm
|
restart_service php$(php_version)-fpm
|
||||||
|
|
||||||
# Open ports.
|
# Open ports.
|
||||||
ufw_allow http
|
ufw_allow http
|
||||||
|
@ -33,8 +33,9 @@ VERSION=1.4.11
|
|||||||
HASH=3877f0e70f29e7d0612155632e48c3db1e626be3
|
HASH=3877f0e70f29e7d0612155632e48c3db1e626be3
|
||||||
PERSISTENT_LOGIN_VERSION=6b3fc450cae23ccb2f393d0ef67aa319e877e435 # version 5.2.0
|
PERSISTENT_LOGIN_VERSION=6b3fc450cae23ccb2f393d0ef67aa319e877e435 # version 5.2.0
|
||||||
HTML5_NOTIFIER_VERSION=68d9ca194212e15b3c7225eb6085dbcf02fd13d7 # version 0.6.4+
|
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
|
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
|
# download and verify the full release of the carddav plugin
|
||||||
wget_verify \
|
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 \
|
$CARDDAV_HASH \
|
||||||
/tmp/carddav.zip
|
/tmp/carddav.tar.gz
|
||||||
|
|
||||||
# unzip and cleanup
|
# unzip and cleanup
|
||||||
unzip -q /tmp/carddav.zip -d ${RCM_PLUGIN_DIR}
|
# unzip -q /tmp/carddav.tar.gz -d ${RCM_PLUGIN_DIR}
|
||||||
rm -f /tmp/carddav.zip
|
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
|
# record the version we've installed
|
||||||
echo $UPDATE_KEY > ${RCM_DIR}/version
|
echo $UPDATE_KEY > ${RCM_DIR}/version
|
||||||
@ -116,7 +118,7 @@ cat > $RCM_CONFIG <<EOF;
|
|||||||
'verify_peer_name' => false,
|
'verify_peer_name' => false,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
\$config['imap_timeout'] = 15;
|
\$config['imap_timeout'] = 180;
|
||||||
\$config['smtp_server'] = 'tls://127.0.0.1';
|
\$config['smtp_server'] = 'tls://127.0.0.1';
|
||||||
\$config['smtp_conn_options'] = array(
|
\$config['smtp_conn_options'] = array(
|
||||||
'ssl' => array(
|
'ssl' => array(
|
||||||
@ -199,4 +201,4 @@ chmod 664 $STORAGE_ROOT/mail/roundcube/roundcube.sqlite
|
|||||||
|
|
||||||
# Enable PHP modules.
|
# Enable PHP modules.
|
||||||
phpenmod -v php mcrypt imap
|
phpenmod -v php mcrypt imap
|
||||||
restart_service php7.2-fpm
|
restart_service php$(php_version)-fpm
|
||||||
|
BIN
tools/goiplookup.gz
Normal file
BIN
tools/goiplookup.gz
Normal file
Binary file not shown.
@ -26,7 +26,7 @@ if [ ! -f $1/config.php ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Restoring backup from $1"
|
echo "Restoring backup from $1"
|
||||||
service php7.2-fpm stop
|
service php7.3-fpm stop
|
||||||
|
|
||||||
# remove the current ownCloud/Nextcloud installation
|
# remove the current ownCloud/Nextcloud installation
|
||||||
rm -rf /usr/local/lib/owncloud/
|
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
|
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"
|
echo "Done"
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
source /etc/mailinabox.conf # load global vars
|
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
|
test -z "$1" || ADMIN=$1
|
||||||
|
|
||||||
echo I am going to unlock admin features for $ADMIN.
|
echo I am going to unlock admin features for $ADMIN.
|
||||||
|
Loading…
Reference in New Issue
Block a user