diff --git a/roles/mgrote_munin_server/defaults/main.yml b/roles/mgrote_munin_server/defaults/main.yml
new file mode 100644
index 00000000..46ee4e39
--- /dev/null
+++ b/roles/mgrote_munin_server/defaults/main.yml
@@ -0,0 +1,26 @@
+---
+munin_packages:
+ - cron
+ - munin
+ - nginx
+ - apache2
+ - wget
+ - libapache2-mod-fcgid
+ - libcgi-fast-perl
+ - ssmtp
+ - perl
+ - mailutils
+ - curl tzdata
+ - munin-node
+ - libfile-readbackwards-perl
+apt_packages_physical:
+ - hddtemp
+ - ipmitool
+ - powertop
+ - s-tui
+apt_packages_vm:
+ - qemu-guest-agent
+ - open-vm-tools
+apt_packages_extra:
+apt_packages_absent:
+apt_packages_internet:
diff --git a/roles/mgrote_munin_server/tasks/main.yml b/roles/mgrote_munin_server/tasks/main.yml
new file mode 100644
index 00000000..8eb42f37
--- /dev/null
+++ b/roles/mgrote_munin_server/tasks/main.yml
@@ -0,0 +1,39 @@
+---
+- name: ensure packages are installed
+ become: true
+ ansible.builtin.package:
+ name: "{{ munin_packages }}"
+ state: present
+
+
+
+RUN (cp /etc/munin/apache24.conf /etc/apache2/sites-available/000-default.conf) && \
+ (sed -i 's/^Alias.*/Alias \/ \/var\/cache\/munin\/www\//g' /etc/apache2/sites-available/000-default.conf) && \
+ (sed -i 's/Allow from .*/Satisfy Any/g' /etc/apache2/sites-available/000-default.conf) && \
+ (sed -i 's/Order allow,deny.*/Allow from all/g' /etc/apache2/sites-available/000-default.conf) && \
+ (mkdir -p /var/run/munin && \
+ chown -R munin:munin /var/run/munin) && \
+ (chfn -f 'munin' root) && \
+ (/usr/sbin/a2enmod fcgid) && \
+ rm -rf /etc/munin/plugins && \
+ mkdir -p /etc/munin/plugins
+
+COPY run.sh /usr/local/bin/run
+COPY munin_stats /etc/munin/plugins/munin_stats
+COPY munin_update /etc/munin/plugins/munin_update
+
+RUN chmod +x /etc/munin/plugins/munin_stats && \
+ chmod +x /etc/munin/plugins/munin_update && \
+ chmod +x /usr/local/bin/run
+
+COPY 000-default.conf /etc/apache2/sites-available/000-default.conf
+COPY logrotate-munin /etc/logrotate.d/munin
+COPY munin.conf /etc/munin/munin.conf
+COPY munin-node.conf /etc/munin/munin-node.conf
+COPY ssmtp.conf /etc/ssmtp/ssmtp.conf
+COPY revaliases /etc/ssmtp/revaliases
+COPY munin_mail.conf /etc/munin/munin-conf.d/munin_mail.conf
+
+
+# launcher
+CMD ["/usr/local/bin/run"]
diff --git a/roles/mgrote_munin_server/templates/000-default.conf b/roles/mgrote_munin_server/templates/000-default.conf
new file mode 100644
index 00000000..aea048ab
--- /dev/null
+++ b/roles/mgrote_munin_server/templates/000-default.conf
@@ -0,0 +1,54 @@
+Documentroot /var/cache/munin/www
+
+ServerName localhost.localdomain
+
+
+ Allow from all
+ Satisfy Any
+ Options none
+
+ ExpiresActive On
+ ExpiresDefault M310
+
+
+
+Alias /munin-cgi/ /usr/lib/munin/cgi/
+
+ Allow from all
+ Satisfy Any
+ Options +ExecCGI
+
+ SetHandler fcgid-script
+
+
+ SetHandler cgi-script
+
+
+
+
+
+ Allow from all
+ Satisfy Any
+
+
+
+ Allow from all
+ Satisfy Any
+
+ SetHandler fcgid-script
+
+
+ SetHandler cgi-script
+
+
+
+
+ Allow from all
+ Satisfy Any
+
+ SetHandler fcgid-script
+
+
+ SetHandler cgi-script
+
+
diff --git a/roles/mgrote_munin_server/templates/Dockerfile b/roles/mgrote_munin_server/templates/Dockerfile
new file mode 100644
index 00000000..897feeb1
--- /dev/null
+++ b/roles/mgrote_munin_server/templates/Dockerfile
@@ -0,0 +1,62 @@
+FROM ubuntu:24.04
+
+# hadolint ignore=DL3008
+RUN apt-get update && \
+ RUNLEVEL=1 DEBIAN_FRONTEND=noninteractive apt-get -y --no-install-recommends install \
+ cron \
+ munin \
+ nginx \
+ apache2 \
+ wget \
+ libapache2-mod-fcgid \
+ libcgi-fast-perl \
+ ssmtp \
+ perl \
+ mailutils \
+ curl tzdata \
+ munin-node \
+ autoconf \
+ libfile-readbackwards-perl \
+ && apt-get clean && \
+ rm -rf /var/lib/apt/lists/* /var/tmp/* /tmp/*
+
+RUN (cp /etc/munin/apache24.conf /etc/apache2/sites-available/000-default.conf) && \
+ (sed -i 's/^Alias.*/Alias \/ \/var\/cache\/munin\/www\//g' /etc/apache2/sites-available/000-default.conf) && \
+ (sed -i 's/Allow from .*/Satisfy Any/g' /etc/apache2/sites-available/000-default.conf) && \
+ (sed -i 's/Order allow,deny.*/Allow from all/g' /etc/apache2/sites-available/000-default.conf) && \
+ (mkdir -p /var/run/munin && \
+ chown -R munin:munin /var/run/munin) && \
+ (chfn -f 'munin' root) && \
+ (/usr/sbin/a2enmod fcgid) && \
+ rm -rf /etc/munin/plugins && \
+ mkdir -p /etc/munin/plugins
+
+COPY run.sh /usr/local/bin/run
+COPY munin_stats /etc/munin/plugins/munin_stats
+COPY munin_update /etc/munin/plugins/munin_update
+
+RUN chmod +x /etc/munin/plugins/munin_stats && \
+ chmod +x /etc/munin/plugins/munin_update && \
+ chmod +x /usr/local/bin/run
+
+COPY 000-default.conf /etc/apache2/sites-available/000-default.conf
+COPY logrotate-munin /etc/logrotate.d/munin
+COPY munin.conf /etc/munin/munin.conf
+COPY munin-node.conf /etc/munin/munin-node.conf
+COPY ssmtp.conf /etc/ssmtp/ssmtp.conf
+COPY revaliases /etc/ssmtp/revaliases
+COPY munin_mail.conf /etc/munin/munin-conf.d/munin_mail.conf
+
+# persist
+VOLUME /var/lib/munin
+VOLUME /var/log/munin
+VOLUME /var/cache/munin
+
+EXPOSE 80
+
+# health check
+HEALTHCHECK --interval=5m --timeout=3s \
+ CMD curl -f http://localhost/munin/ || exit 1
+
+# launcher
+CMD ["/usr/local/bin/run"]
diff --git a/roles/mgrote_munin_server/templates/logrotate-munin b/roles/mgrote_munin_server/templates/logrotate-munin
new file mode 100644
index 00000000..1bd78d64
--- /dev/null
+++ b/roles/mgrote_munin_server/templates/logrotate-munin
@@ -0,0 +1,51 @@
+/var/log/munin/munin-update.log {
+ daily
+ missingok
+ rotate 7
+ compress
+ delaycompress
+ notifempty
+ create 640 munin adm
+}
+
+/var/log/munin/munin-graph.log {
+ daily
+ missingok
+ rotate 7
+ compress
+ delaycompress
+ notifempty
+ create 660 munin munin
+}
+
+/var/log/munin/munin-html.log {
+ daily
+ missingok
+ rotate 7
+ compress
+ delaycompress
+ notifempty
+ create 640 munin adm
+}
+
+/var/log/munin/munin-limits.log {
+ daily
+ missingok
+ rotate 7
+ compress
+ delaycompress
+ notifempty
+ create 640 munin adm
+}
+
+/var/log/munin/munin-cgi-graph.log {
+ daily
+ missingok
+ rotate 7
+ compress
+ delaycompress
+ notifempty
+ #create 640 www-data adm
+ # see http://munin-monitoring.org/ticket/1152
+ copytruncate
+}
diff --git a/roles/mgrote_munin_server/templates/munin-node.conf b/roles/mgrote_munin_server/templates/munin-node.conf
new file mode 100644
index 00000000..93202a12
--- /dev/null
+++ b/roles/mgrote_munin_server/templates/munin-node.conf
@@ -0,0 +1,62 @@
+#
+# Example config-file for munin-node
+#
+
+log_level 4
+log_file /var/log/munin/munin-node.log
+pid_file /var/run/munin/munin-node.pid
+
+background 1
+setsid 1
+
+user root
+group root
+
+# This is the timeout for the whole transaction.
+# Units are in sec. Default is 15 min
+#
+# global_timeout 900
+
+# This is the timeout for each plugin.
+# Units are in sec. Default is 1 min
+#
+# timeout 60
+
+# Regexps for files to ignore
+ignore_file [\#~]$
+ignore_file DEADJOE$
+ignore_file \.bak$
+ignore_file %$
+ignore_file \.dpkg-(tmp|new|old|dist)$
+ignore_file \.rpm(save|new)$
+ignore_file \.pod$
+
+# Set this if the client doesn't report the correct hostname when
+# telnetting to localhost, port 4949
+#
+host_name munin-master
+
+# A list of addresses that are allowed to connect. This must be a
+# regular expression, since Net::Server does not understand CIDR-style
+# network notation unless the perl module Net::CIDR is installed. You
+# may repeat the allow line as many times as you'd like
+
+allow ^127\.0\.0\.1$
+allow ^::1$
+
+# If you have installed the Net::CIDR perl module, you can use one or more
+# cidr_allow and cidr_deny address/mask patterns. A connecting client must
+# match any cidr_allow, and not match any cidr_deny. Note that a netmask
+# *must* be provided, even if it's /32
+#
+# Example:
+#
+# cidr_allow 127.0.0.1/32
+# cidr_allow 192.0.2.0/24
+# cidr_deny 192.0.2.42/32
+
+# Which address to bind to;
+host 0.0.0.0
+
+# And which port
+port 4949
diff --git a/roles/mgrote_munin_server/templates/munin.conf b/roles/mgrote_munin_server/templates/munin.conf
new file mode 100644
index 00000000..014f5534
--- /dev/null
+++ b/roles/mgrote_munin_server/templates/munin.conf
@@ -0,0 +1,7 @@
+includedir /etc/munin/munin-conf.d
+
+[munin-container]
+ address localhost
+ use_node_name yes
+
+# remote host
diff --git a/roles/mgrote_munin_server/templates/munin_mail.conf b/roles/mgrote_munin_server/templates/munin_mail.conf
new file mode 100644
index 00000000..834245de
--- /dev/null
+++ b/roles/mgrote_munin_server/templates/munin_mail.conf
@@ -0,0 +1,7 @@
+contact.hosting.command mail -s "[MUNIN] Alert ${var:graph_title} for ${var:host}" mailcontact
+contact.hosting.max_messages 1
+# if activated mail will be send at each check (every 5mn)
+# contact.hosting.always_send critical
+
+# to prevent flooding log file because missing documented contact parameters "no"
+contact.no.command awk '{ print "[MUNIN] Alert ${var:graph_title} for ${var:host}" }' /dev/null
diff --git a/roles/mgrote_munin_server/templates/munin_stats b/roles/mgrote_munin_server/templates/munin_stats
new file mode 100644
index 00000000..c03cab0a
--- /dev/null
+++ b/roles/mgrote_munin_server/templates/munin_stats
@@ -0,0 +1,118 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 2006-2009 Rodolphe QuiƩdeville
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2 dated June,
+# 1991.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+#
+# Magic markers (used by munin-node-configure and some installation scripts):
+#%# family=auto
+#%# capabilities=autoconf
+
+use strict;
+use warnings;
+
+use Munin::Plugin;
+
+
+my $missing_module = undef;
+$missing_module = "File::ReadBackwards" unless (eval "require File::ReadBackwards");
+
+my @logs = qw/update graph html limits/;
+my $logdir = ($ENV{'logdir'} || $ENV{'MUNIN_LOGDIR'} || '/var/log/munin');
+
+if ($ENV{'fields'}) {
+ @logs = split(/ +/, $ENV{'fields'});
+}
+
+sub uses_graph_cron {
+ my $log_file = $_[0];
+ my $bw = File::ReadBackwards->new($log_file) or
+ die "can't read 'log_file' $!";
+ if (defined(my $log_line = $bw->readline)) {
+ if ($log_line =~ ('.*graphing is cgi, do nothing$')) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else {
+ return 1;
+ }
+}
+
+
+if ($ARGV[0] and $ARGV[0] eq 'autoconf') {
+ my $munin_update_location =
+ "$Munin::Common::Defaults::MUNIN_LIBDIR/munin-update";
+
+ if (! -e $munin_update_location) {
+ print "no (munin-update was not found at $munin_update_location)\n";
+ } elsif (! -x $munin_update_location) {
+ print "no ($munin_update_location was found, but is not executable)\n";
+ } elsif (defined($missing_module)) {
+ print "no (missing Perl module: '$missing_module')\n";
+ } else {
+ print "yes\n";
+ }
+ exit 0;
+}
+
+if ($ARGV[0] and $ARGV[0] eq "config") {
+ print "graph_title Munin processing time\n",
+ "graph_info This graph shows the run time of the four different processes making up a munin-master run. Munin-master is run from cron every 5 minutes and we want each of the programmes in munin-master to complete before the next instance starts. If munin-update uses too long time to run please see the munin-update graph to determine which host is slowing it down.\n",
+ "graph_args --base 1000 -l 0\n",
+ "graph_scale yes\n",
+ "graph_vlabel seconds\n",
+ "graph_category munin\n";
+ foreach my $log (@logs) {
+ print "$log.label munin $log\n";
+ print "$log.draw AREASTACK\n";
+
+ next unless $log eq "update" || $log eq "graph";
+
+ print_thresholds("$log", undef, undef, 240, 285);
+ }
+ exit 0;
+}
+
+
+if (defined($missing_module)) {
+ die "Failed to run due to missing Perl module '$missing_module'";
+}
+
+foreach my $log (@logs) {
+ my $logfile = "$logdir/munin-$log.log";
+ my $time = 'U';
+
+ if (! -r $logfile) {
+ print "$log.extinfo Can't open $logfile for reading\n";
+ print "$log.value $time\n";
+ next;
+ }
+
+ my $bw = File::ReadBackwards->new("$logdir/munin-$log.log") or
+ die "can't read 'log_file' $!";
+ my $found_previous_finished = 0;
+ while(defined(my $log_line = $bw->readline) && $found_previous_finished == 0) {
+ if ($log_line =~ (/(finished|generated) \((\d+\.\d+)\ssec\)$/)) {
+ $time = $2;
+ $found_previous_finished = 1;
+ }
+ }
+
+ if ($log ne "graph" || uses_graph_cron("$logdir/munin-$log.log")) {
+ print "$log.value $time\n";
+ }
+}
diff --git a/roles/mgrote_munin_server/templates/munin_update b/roles/mgrote_munin_server/templates/munin_update
new file mode 100644
index 00000000..174d87db
--- /dev/null
+++ b/roles/mgrote_munin_server/templates/munin_update
@@ -0,0 +1,123 @@
+#!/bin/sh
+
+: <<=cut
+
+=head1 NAME
+
+munin_update - Munin plugin to graph the time to query about each host from the nodes.
+
+=head1 APPLICABLE SYSTEMS
+
+Munin master servers.
+
+=head1 CONFIGURATION
+
+Normally needs no configuration. You may configure it with the
+following parameter:
+
+ [munin*]
+ env.UPDATE_STATSFILE .../munin-update.stats
+ env.MUNIN_UPDATE_LOCACTION .../munin-update
+
+The first is the statistics file for munin update.
+
+The exact location of this file is package/site specific, but
+munin_update will know where it is unless you have made changes.
+
+=head1 INTERPRETATION
+
+The script reads the munin-update "stats" file to determine how long
+it takes to query the nodes about each host configured in Munin.
+
+Munin is run from cron every 5 minutes and before the next run of
+munin-update the previous run needs to be done. Each run of
+munin-update forks one process pr. host that needs to get data
+collected, so all collection runs in parallel.
+
+Any host that is slow, for example slower than 4 miniutes, causes a
+risk that the next run of munin-update must be canceled due to the
+lateness of the previous run. In such cases there will be single line
+gaps in the "by day" graph.
+
+Keep your hosts updating quickly and all will be well.
+
+=head1 MAGIC MARKERS
+
+ #%# family=manual
+ #%# capabilities=autoconf
+
+=head1 BUGS
+
+Munin-update is always run at the same time as this plugin runs -
+therefore the stats file may be incompletely written and the plugin
+will likely show a incomplete list of hosts. It should be using
+munin-update.old-stats, which is not currently even made.
+
+Munin-update removes the "domain" information on all hosts. If there
+are two hosts with the same host name in different domains then one of
+them will be disappeared by the munin-update collection process.
+
+=head1 AUTHOR
+
+The munin_update plugin has been included in munin for many years (at
+least 2004). The most likely author is one of the original munin team.
+
+Documentation and updating to 2009 for Munin 1.4 by Nicolai Langfeldt.
+
+(C) 2004-2009 The Munin Team, Redpill Linpro AS
+
+=head1 LICENSE
+
+GPLv2
+
+=cut
+
+. "$MUNIN_LIBDIR/plugins/plugin.sh"
+
+
+UPDATE_STATSFILE=${UPDATE_STATSFILE:-$MUNIN_DBDIR/munin-update.stats}
+MUNIN_UPDATE_LOCATION=${MUNIN_UPDATE_LOCATION:-$MUNIN_LIBDIR/munin-update}
+
+
+if [ "$1" = "autoconf" ]; then
+ if [ -e "$MUNIN_UPDATE_LOCATION" ] ; then
+ echo "yes"
+ else
+ echo "no ($MUNIN_UPDATE_LOCATION is not present so this is not a munin-master)"
+ fi
+ exit 0
+fi
+
+if [ "$1" = "config" ]; then
+ [ -f "$UPDATE_STATSFILE" ] || {
+ echo 'graph_title Plugin error'
+ echo "graph_info Plugin cannot read stats file $UPDATE_STATSFILE"
+ echo 'error.label Error'
+ echo 'error.critical 1'
+ exit 0
+ }
+
+ echo 'graph_title Munin-update'
+ echo 'graph_vlabel seconds'
+ echo 'graph_category munin'
+ echo 'graph_info This graph shows the time it takes to collect data from each hosts that munin collects data on. Munin-master is run from cron every 5 minutes and we want each of the munin-update runs to complete before the next one starts. If munin-update uses too long time to run on one host run it with --debug to determine which plugin(s) are slow and solve the problem with them if possible.'
+ sed '/^UD|/!d; s/.*;//; s/|/ /;' < "$UPDATE_STATSFILE" | sort |
+ while read -r i j; do
+ name="$(clean_fieldname "$i")"
+ echo "$name.label $i"
+ warning=${warning:-240} critical=${critical:-285} print_thresholds "$name"
+ done
+ exit 0
+fi
+
+[ -f "$UPDATE_STATSFILE" ] || {
+ echo 'error.value 1'
+ echo "error.extinfo Plugin cannot read stats file $UPDATE_STATSFILE"
+ exit 0
+}
+
+sed '/^UD|/!d; s/.*;//; s/|/ /;' < "$UPDATE_STATSFILE" | sort |
+while read -r i j; do
+ name="$(clean_fieldname "$i")"
+ echo "$name.value $j"
+done
diff --git a/roles/mgrote_munin_server/templates/renovate.json b/roles/mgrote_munin_server/templates/renovate.json
new file mode 100644
index 00000000..eb381828
--- /dev/null
+++ b/roles/mgrote_munin_server/templates/renovate.json
@@ -0,0 +1,13 @@
+{
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
+ "extends": [
+ ":dependencyDashboard",
+ ":semanticPrefixFixDepsChoreOthers",
+ ":ignoreModulesAndTests",
+ "group:monorepos",
+ "group:recommended",
+ "replacements:all",
+ "workarounds:all",
+ "mergeConfidence:all-badges"
+ ]
+}
diff --git a/roles/mgrote_munin_server/templates/revaliases b/roles/mgrote_munin_server/templates/revaliases
new file mode 100644
index 00000000..1f834110
--- /dev/null
+++ b/roles/mgrote_munin_server/templates/revaliases
@@ -0,0 +1,8 @@
+# sSMTP aliases
+#
+# Format: local_account:outgoing_address:mailhub
+#
+# Example: root:your_login@your.domain:mailhub.your.domain[:port]
+# where [:port] is an optional port number that defaults to 25.
+root:mailfrom:mailserver:mailport
+munin:mailfrom:mailserver:mailport
diff --git a/roles/mgrote_munin_server/templates/run.sh b/roles/mgrote_munin_server/templates/run.sh
new file mode 100644
index 00000000..d0dadfb9
--- /dev/null
+++ b/roles/mgrote_munin_server/templates/run.sh
@@ -0,0 +1,106 @@
+#!/bin/bash
+
+# timezone settings
+TZ=${TZ:="Europe/Paris"}
+echo $TZ > /etc/timezone
+# workaround https://bugs.launchpad.net/ubuntu/+source/tzdata/+bug/1554806
+rm /etc/localtime
+dpkg-reconfigure -f noninteractive tzdata
+
+# change cron setting for updates
+CRONDELAY=${CRONDELAY:=5}
+sed -i "s/\*\/5/\*\/$CRONDELAY/g" /etc/cron.d/munin
+
+# configure default node name
+THISNODENAME=${THISNODENAME:="munin"}
+sed -i "s/^\[localhost\.localdomain\]/\[$THISNODENAME\]/g" /etc/munin/munin.conf
+
+# configure default node IP
+THISNODEIP=${THISNODEIP:="127.0.0.1"}
+sed -i "s/^\( *address\) 127\.0\.0\.1\$/\1 $THISNODEIP/" /etc/munin/munin.conf
+
+# configure default servername
+THISSERVERNAME=${SERVERNAME:="munin"}
+sed -i "s/^\[localhost\.localdomain\]/\[$SERVERNAME\]/g" /etc/apache2/sites-available/000-default.conf
+
+# configure mail notification
+if [[ -n "$MAILCONTACT" && -n "$MAILSERVER" && -n "$MAILPORT" && -n "$MAILUSER" && -n "$MAILPASSWORD" && -n "$MAILDOMAIN" ]] ; then
+ MAILCONTACT=${MAILCONTACT:="contact@domain.test"}
+ sed -i "s/mailcontact/$MAILCONTACT/g" /etc/ssmtp/ssmtp.conf
+ sed -i "s/mailcontact/$MAILCONTACT/g" /etc/munin/munin-conf.d/munin_mail.conf
+ MAILSERVER=${MAILSERVER:="mail.domain.test"}
+ sed -i "s/mailserver/$MAILSERVER/g" /etc/ssmtp/ssmtp.conf
+ sed -i "s/mailserver/$MAILSERVER/g" /etc/ssmtp/revaliases
+ MAILPORT=${MAILPORT:="25"}
+ sed -i "s/mailport/$MAILPORT/g" /etc/ssmtp/ssmtp.conf
+ sed -i "s/mailport/$MAILPORT/g" /etc/ssmtp/revaliases
+ MAILUSER=${MAILUSER:="alert@domain.test"}
+ sed -i "s/mailuser/$MAILUSER/g" /etc/ssmtp/ssmtp.conf
+ MAILFROM=${MAILFROM:="munin@domain.test"}
+ sed -i "s/mailfrom/$MAILFROM/g" /etc/ssmtp/revaliases
+ MAILPASSWORD=${MAILPASSWORD:="XXXXXXXXX"}
+ sed -i "s/mailpassword/$MAILPASSWORD/g" /etc/ssmtp/ssmtp.conf
+ MAILDOMAIN=${MAILDOMAIN:="domain.test"}
+ sed -i "s/maildomain/$MAILDOMAIN/g" /etc/ssmtp/ssmtp.conf
+ sed -i "s/mailhost/$MAILDOMAIN/g" /etc/ssmtp/ssmtp.conf
+ MAILNAME=${MAILNAME:="Munin"}
+ sed -i "s/munin application user/$MAILNAME/g" /etc/passwd
+else
+ rm /etc/munin/munin-conf.d/munin_mail.conf /etc/ssmtp/ssmtp.conf
+fi
+
+# generate node list
+NODES=${NODES:-}
+for NODE in $NODES
+do
+ NAME=`echo $NODE | cut -d ':' -f1`
+ HOST=`echo $NODE | cut -d ':' -f2`
+ grep -q "${HOST}$" /etc/munin/munin.conf || cat << EOF >> /etc/munin/munin.conf
+[$NAME]
+ address $HOST
+ use_node_name yes
+
+EOF
+done
+
+# placeholder html to prevent permission error
+if [ ! -f /var/cache/munin/www/index.html ]; then
+ cat << EOF > /var/cache/munin/www/index.html
+
+
+ Munin
+
+
+ Munin has not run yet. Please try again in a few moments.
+
+
+EOF
+ chown -R munin: /var/cache/munin/www/index.html
+fi
+
+# ensure munin folder exist and have right permission
+mkdir -p /var/lib/munin/cgi-tmp /var/cache/munin/www
+chown -R munin:munin /var/lib/munin /var/cache/munin
+chmod -R ugo+rw /var/lib/munin/cgi-tmp
+chown munin:munin /var/log/munin/munin-graph.log
+chown munin:munin /var/log/munin/munin-limits.log
+chown munin:munin /var/log/munin/munin-html.log
+
+# start cron
+/usr/sbin/cron &
+
+# start local munin-node
+/usr/sbin/munin-node > /dev/null 2>&1 &
+
+# confirm nodes
+echo "Using the following munin nodes:"
+echo " $THISNODENAME"
+echo " $NODES"
+
+# start apache
+/usr/sbin/apache2ctl start
+
+# display logs
+touch /var/log/munin/munin-update.log
+chown munin:munin /var/log/munin/munin-update.log
+tail -f /var/log/munin/munin-*.log
diff --git a/roles/mgrote_munin_server/templates/ssmtp.conf b/roles/mgrote_munin_server/templates/ssmtp.conf
new file mode 100644
index 00000000..e8ee9958
--- /dev/null
+++ b/roles/mgrote_munin_server/templates/ssmtp.conf
@@ -0,0 +1,25 @@
+#
+# Config file for sSMTP sendmail
+#
+# The person who gets all mail for userids < 1000
+# Make this empty to disable rewriting.
+root=mailuser
+
+# The place where the mail goes. The actual machine name is required no
+# MX records are consulted. Commonly mailhosts are named mail.domain.com
+mailhub=mailserver:mailport
+AuthUser=mailuser
+AuthPass=mailpassword
+UseTLS=YES
+UseSTARTTLS=YES
+
+# Where will the mail seem to come from?
+rewriteDomain=maildomain
+
+# The full hostname
+hostname=mailhost
+
+# Are users allowed to set their own From: address?
+# YES - Allow the user to specify their own From: address
+# NO - Use the system generated From: address
+FromLineOverride=NO