MTA-Setup

Uit MakerSpace Leiden
Versie door DirkWillem (overleg | bijdragen) op 1 jul 2018 om 12:25 (Virus scan)
Ga naar: navigatie, zoeken

The front end server (mid 2018) runs on Linux; in a `cloud' hosted environment.

Below documents the initial setup of the base machine; followed by the setup for each of the modules.

The final section shows the monthly and annual maintenance cycles.


Setup and rudimentary hardening

  • Get the machine in a known state and install sudo (so we can disable root; and comply with 'named accounts' only policies):
apt update
apt upgrade
apt install sudo certbot certbot-apache moreutils
  • enable ufw and allow the usual ports in IPv4 and IPv6
 for port in 22 25 53 80 443
 do
   ufw allow  $port
 done
 # do this last so we're not kicked out.
 ufw enable
  • create named accounts for each of the admins (you need to get everyones their public SSH key):
 adduser \
  --system \
  --shell /bin/bash \
  --gecos 'Dirk-Willem van Gulik' \
  --group \
  --ingroup admin \
  --disabled-password \
  dirkx
  • Add an ssh key for each of these users
  • check that you can log in; and sudo with at least one of them.
  • Block root login and passwords in /etc/ssh/sshd.conf:
 PermitRootLogin no
 PasswordAuthentication no
 ChallengeResponseAuthentication no
Note: if you did not check the sudo/login of an admin user - they you are about to lock yourself out upon reboot.
  • Edit /etc/sysctl.conf to block spoofing, ICMP broadcast, source-packet routing, send redirect, SYN attacks, Martians and ICM redirects.
  • Prevent IP spoofing for DNS by replacing multi on to nospoof on in /etc/hosts.conf
  • Securing shared memory.
 echo tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0 >> /etc/fstab
  • Make sure we trap all crontab outputs systemctl edit cron.service:
  [Service]
  Environment="MAILTO=noc@makerspaceleiden.nl"
  • Reboot.

Setup of the basic website

We need to first set up a very basic website; in order to be able to fetch the required SSL certificates.

  • Install apache and certbot and the integration glue between the two:
sudo apt install apache2 certbot python-certbot-apache
  • Request the needed certs:
sudo certbot --apache -d makerspaceleiden.nl -d www.makerspaceleiden.nl -d wiki.makerspaceleiden.nl
  • Ensure they get renewed; and that the admins are emailed when this goes wrong:

Setup of the MTA

Log in as one of the admins.

  • Make sure /etc/mailname is set to makerspaceleiden.nl
  • Install postfix and basic mail stuff:
 sudo apt install postfix mailtools postgrey mavisd-new spamassassin clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor  arj bzip2 cabextract cpio file gzip  nomarch pax rar unrar unzip zip
  • Edit the /etc/aliases file to redirect the mail of 'root' and update:
 sudo vi /etc/aliases
 sudo newaliases
  • Edit the certs in /etc/postfix/main.cf
 smtpd_tls_cert_file=/etc/letsencrypt/live/makerspaceleiden.nl/fullchain.pem
 smtpd_tls_key_file=/etc/letsencrypt/live/makerspaceleiden.nl/privkey.pem
  • Give the virus/spam scanner mutual access:
 sudo adduser clamav amavis
 sudo adduser amavis clamav
  • As the amavis user; razor-admin -create and razor-admin -register if needed.
  • Edit /etc/amavis/conf.d/15-content_filter_mode to activate the filters and restart:
 sudo /etc/init.d/amavis restart
  • The whitelist for postgray contains a number of entries for the various deur logging systems:
... to do ...

Setup of WordPress

  • Install enough of the LAMP stack to get going:
 sudo apt install apache2 mysql-server php libapache2-mod-php php-mysql wordpress-theme-twentyseventeen wordpress
  • Secure your mysql install:
 sudo mysql_secure_installation
  • Configure apache:
  cat <<EOM > /etc/apache2/sites-available/wordpress.conf
 <VirtualHost *:80>
     ServerAdmin noc@makerspaceleiden.nl
  
     ServerName        makerspaceleiden.nl
     ServerAlias       www.makerspaceleiden.nl
  
     DocumentRoot /var/www/html
     ErrorLog ${APACHE_LOG_DIR}/error.log
     CustomLog ${APACHE_LOG_DIR}/access.log combined
  
     RewriteEngine On
     RewriteCond %{HTTPS} off
     RewriteRule (.*) https://%{SERVER_NAME}/$1 [R,L]
 </VirtualHost>
 
 Listen *443
 <VirtualHost *:443>
     ServerAdmin noc@makerspaceleiden.nl
     ServerName        makerspaceleiden.nl
     ServerAlias       www.makerspaceleiden.nl
  
     SSLCertificateFile  /etc/letsencrypt/live/makerspaceleiden.nl/fullchain.pem
     SSLCertificateKeyFile /etc/letsencrypt/live/makerspaceleiden.nl/privkey.pem
 
     SSLProtocol all -SSLv2 -SSLv3
     SSLHonorCipherOrder On
     SSLCipherSuite EECDH+AES:EDH+AES:-SHA1:EECDH+RC4:EDH+RC4:RC4-SHA:EECDH+AES256:EDH+AES256:AES256-SHA:!aNULL:!eNULL:!EXP:!LOW:!MD5
 
     DocumentRoot /usr/share/wordpress
 
     ErrorLog ${APACHE_LOG_DIR}/error.log
     CustomLog ${APACHE_LOG_DIR}/access.log combined
  
     <Directory /usr/share/wordpress>
           Options FollowSymLinks
           AllowOverride Limit Options FileInfo
           DirectoryIndex index.php
           Order allow,deny
           Allow from all
     </Directory>
 
     <Directory /usr/share/wordpress/wp-content>
           Options FollowSymLinks
           Order allow,deny
           Allow from all
       </Directory>
        
  </VirtualHost>
  EOM
  • Create a database and a config file (changing yourpasswordhere123):
 cat <<EOM |  sudo mysql --defaults-extra-file=/etc/mysql/debian.cnf
 CREATE DATABASE wordpress;
 GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,ALTER
 ON wordpress.*
 TO wordpress@localhost
 IDENTIFIED BY 'yourpasswordhere123';
 FLUSH PRIVILEGES;
 EOM
 cat <<EOM > /etc/wordpress/config-localhost.php
 <?php
 define('DB_NAME', 'wordpress');
 define('DB_USER', 'wordpress');
 define('DB_PASSWORD', 'yourpasswordhere123');
 define('DB_HOST', 'localhost');
 define('WP_CONTENT_DIR', '/usr/share/wordpress/wp-content');
 define('FS_METHOD', 'direct');
 ?>
  • Secure this file so that only the webserver can see this password.
    sudo chown root:www-data /etc/wordpress/config-localhost.php
    sudo chmod o-rwx,g-wx /etc/wordpress/config-localhost.php
  • Enable, kill default and restart:
  sudo a2ensite wordpress
  sudo a2dissite 000-default 
  sudo systemctl reload apache2
  • Check that it all works by visiting
  httpp://makerspaceleiden.nl/install.php
  • If you want to be able to update in place - be sure to have the wordpress content directory `www-data' owned.

Setup of Media Wiki

  • Install the base packages
 apt install mediawiki imagemagick php-apcu php-intl
  • Create the database:
cat <<EOM |  sudo mysql --defaults-extra-file=/etc/mysql/debian.cnf
CREATE DATABASE mediawiki;
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,ALTER,INDEX
ON mediawiki.*
TO mediawiki@localhost
IDENTIFIED BY 'yourpasswordhere12443';
FLUSH PRIVILEGES;
EOM
  • Restart apache.
  • Go to the wiki - and use the config values from above DB setup.,
  • Follow the instructions and copy the generated LocalSettings.php to the specified location.
  • Add the various users.

making a backup and importing it

  • Backup script:
 #!/bin/sh
 set -e
 set -x
 D=`date +%Y%m%d%H%M%S`
 mkdir media-wiki-backup.$D
 
 cd media-wiki-backup.$D
 
 mysqldump --user=wikiuser --password="XXXX" wikidb > file.sql
 mysqldump --user=wikiuser --password="XXXX" wikidb --xml > file.xml
 
 cp -r /usr/local/www/mediawiki/images .
 cp /usr/local/www/mediawiki/LocalSettings.php .
 
 cd ..
 tar zcf media-wiki-backup-$D.tgz media-wiki-backup.$D
 rm -rf  media-wiki-backup.$D
  • Dump the full wiki:
    jexec mls  ... script ..
  • Copy the file across.
  • Import it on the other machine
  #!/bin/sh
  set -ex
  
  if ! test -f latest.tgz; then
   		echo no last dump.
   		exit 1
   fi
   mkdir tmp.$$
   cd tmp.$$
   tar zxf ../latest.tgz
   (
   cd *
   
   rm -rf /var/lib/mediawiki/cache /var/lib/mediawiki/images
   
   mkdir import /var/lib/mediawiki/cache /var/lib/mediawiki/images
   cp -r images/? /var/lib/mediawiki/images
   chown -R www-data:www-data /var/lib/mediawiki/images  /var/lib/mediawiki/cache
   
   cat <<EOM |  sudo mysql --defaults-extra-file=/etc/mysql/debian.cnf
   DROP DATABASE mediawiki;
   CREATE DATABASE mediawiki;
   GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,ALTER,INDEX
   ON mediawiki.*
   TO mediawiki@localhost
   IDENTIFIED BY 'XXXX';
   FLUSH PRIVILEGES;
   EOM
  
   cat file.sql | sudo mysql --defaults-extra-file=/etc/mysql/debian.cnf mediawiki
  
   sudo -u www-data /usr/share/mediawiki/maintenance/update.php
   sudo -u www-data php  /usr/share/mediawiki/maintenance/cleanupImages.php
   sudo -u www-data php /usr/share/mediawiki/maintenance/rebuildall.php 
   sudo -u www-data php /usr/share/mediawiki/maintenance/rebuildImages.php 
   
   ) || exit 1
   rm -rf tmp.$$
   exit $?


Monthly Reporting of deelnemers count

The provider has set up a crontab (through their support desk, manual action) that emails a uu-encoded gzipped lists of subscribers to all list owners.

  • The user 'listreporter' has been created as an alias in /etc/aliases
 listreporter: |/etc/mailman/listreporter.sh
  • and is activated with newaliases.

This is wired up to a swapping script (requiring apt install moretools) and a script that is somewhat paranoid and parses/unpacks the email:

 #!/bin/sh
 set -e
 umask 077
 test -x /etc/mailman/listreporter.pl || exit 0
 TMPDIR=${TMPDIR:-/tmp}
 TMPDIR=${TMPDIR}/mailmanlistreporter.$$
 (
 	mkdir $TMPDIR
 	cd $TMPDIR
 	cat > in.msg
 	/usr/bin/perl /etc/mailman/listreporter.pl
  ) 2>&1 | ifne mail -s "Fault with the list reporter." noc@webweaving.org
  rm -rf "${TMPDIR}"
  exit 0

This is then wired to the script sending out the actual email:

  #!/usr/bin/perl 
  # use strict;
  use IO::CaptureOutput qw/capture_exec/;
  
  umask(077);
  
  open(STDIN,"in.msg") or die "Could not open msg file: $!\n";
  
  my $list;
  my $subject;
  
  while(<STDIN>) {
          last if m/^\s*$/;
          $subject = $1 if m/^Subject\s*:\s*(.*)$/;
  };
  close(STDIN);
  
  open STDIN, '</dev/null'; # Prevent warnings deep down in IO capture.
  
  $list = $1 if $subject =~ m/List subscriber file:\s*(\S+)/;
  
  # exit 0 unless $list;
  
  die "Not the right subject <$subject>\n" unless $list;
  die "Not a list I manage." unless $list eq 'deelnemers';
  
  my ($stdout, $stderr, $success, $exit_code) = capture_exec("munpack","-q","in.msg");
  
  die "Unpacking failed: $!\n" unless $exit_code == 0;
  
  my $d = ;
  foreach my $f (<subscribers.$list.*.gz>) {
          next unless $f =~ m/subscribers.$list.([0-9\-]+).txt.gz/;
          $d = $1;
  
          system("gunzip", $f) == 0
                  or die "Could not unpack $f\n";
          $f =~ s/.gz//;
          open(FH,$f) or die "Could not open subscriber list";
          my @list = ();
          while(<FH>) {
                  chomp;
                  s/\s*#.*//;
                  s/\P{IsPrint}//g;
                  next if m/^\s*$/;
                  push @list, $_;
          };
          my $count= @list;
  
          open(FH,"| mail -s 'Makerspace Leiden, $count $list on $d' -aFrom:hetbestuur\@makerspaceleiden.nl  $list\@makerspaceleiden.nl")
                  or die "Cannot open pipe.\n";
  
          print FH <<"EOM";
  Hello All,
  
  We have currently $count makers united, listed below:
  
  Your can edit your own information here:
  
          https://mailman.makerspaceleiden.nl/mailman/options/deelnemers
  
  and this is also where you can switch to a digtest (just one big message/day)
  or see the archive of historic messages.
  
  EOM
          print FH join("\n", @list);
          print FH "\n-- \nStiching Makerspace Leiden / hetbestuur@makerspaceleiden.nl\n\n";
          close(FH);
  
          exit(0);
  }


Virus scan

There is a malware/virus scan set up across the uploads; with automatic refresh of the signature DBs:

... todo