diff --git a/files/usr/local/bin/logs-to-archive.sh b/files/usr/local/bin/logs-to-archive.sh
new file mode 100644
index 0000000000000000000000000000000000000000..de3382e7eef533237f18f0a0775de0eeb35f9ce2
--- /dev/null
+++ b/files/usr/local/bin/logs-to-archive.sh
@@ -0,0 +1,130 @@
+#!/usr/bin/env bash
+
+### META
+# AUTHORS:
+#       - Jörg Sachse (<Joerg.Sachse@slub-dresden.de>)
+
+#hh logs-to-archive.sh - moves old logs to logarchive directory
+#hh
+#hh Usage: logs-to-archive.sh [-h] [-V] [-m] [-M]
+#hh
+#hh Options:
+#hh     You can use the following CLI arguments to configure the behaviour of
+#hh     scriptname.sh. Please note that the CLI arguments need to be space
+#hh     separated. Combining arguments like "-cw" is currently NOT supported.
+#hh
+#hh     -h, --help
+#hh             Show this help and exit.
+#hh     -V, --version
+#hh             Show version number and exit.
+#hh     -m, --man, --manpage, --manual
+#hh             Create a manpage from this help section and exit.
+#hh             Requires "help2man".
+#hh     -M, --showman
+#hh             Print the Manpage.
+#hh             Requires "help2man".
+#hh
+#hh Examples:
+#hh     scriptname.sh -flag         What happens here?
+
+
+
+### DEFAULTS
+
+RED="\\e[31m"
+WHITE="\\e[0m"
+ERROR="${RED}[ERROR]\t${WHITE}"
+# INFO="[INFO]\t"
+
+
+
+### INIT
+
+# SCRIPTPATH="$( dirname "$( realpath "$0" )" )"
+# SCRIPTNAME="$( basename "${0}" )"
+
+# list external required binaries here (space separated)
+REQUIREMENTS="help2man man gzip"
+for REQUIREMENT in ${REQUIREMENTS}; do
+        command -v "${REQUIREMENT}" >/dev/null 2>&1 || { echo >&2 "${ERROR} '${REQUIREMENT}' required but not installed. Aborting."; exit 1; }
+done
+
+
+
+### FUNCTIONS
+
+# Don't just call this function "help()", as that's a reserved command in Bash.
+comment_help() {
+    sed -rn 's/^#hh ?//;T;p' "$0"
+}
+
+create_manpage(){
+        # https://www.gnu.org/software/help2man/
+        help2man --section 1 --source="SLUB Dresden" --no-info "${0}" | gzip > ./"$( basename "${0}" ".sh" ).gz"
+}
+
+show_manpage(){
+        help2man --section 1 --source="SLUB Dresden" --no-info "${0}" | man -l -
+}
+
+get_cli_args(){
+        while [[ $# -gt 0 ]]; do
+                case ${1} in
+                        -h|--help)
+                                comment_help
+                                exit 0
+                                ;;
+                        -V|--version)
+                                echo "$( basename "${0}" ) v1.0.0"
+                                echo -e "\n\nCopyright (C)\n"
+                                echo "This software is licensed under the GNU General Public License version 3 (GNU GPLv3)."
+                                exit 0
+                                ;;
+                        -m|--man|--manpage|--manual)
+                                create_manpage
+                                exit 0
+                                ;;
+                        -M|--showman)
+                                show_manpage
+                                exit 0
+                                ;;
+                        *)
+                                echo "'${1}' is not a valid parameter. Please use '$( basename "${0}" ) --help'. Exiting."
+                                exit 1
+                                ;;
+                esac
+        done
+}
+
+
+
+### MAIN
+
+get_cli_args "${@}"
+
+LOGDIR="/operational_shared/logs/"
+if [[ -d "${LOGDIR}/${HOSTNAME}/" ]]; then
+	cd "${LOGDIR}/${HOSTNAME}/" || exit 1
+else
+	cd "${LOGDIR}/${HOSTNAME}.$( dnsdomainname )/" || exit 1
+fi
+LOGARCHIVE_BASE="$( pwd )/log_archive/"
+
+read -r CURRENT_YEAR CURRENT_MONTH <<< "$( IFS=" " date '+%Y %m' )"
+
+for LOGFILE in *; do
+	read -r YEAR MONTH <<< "$( IFS=" " echo "${LOGFILE}" |  sed -r -n "s/(cantaloupe_access-|cantaloupe_application-|gc\.log\.|server\.log\.|solr\.log\.)(20..)-(..)-...*/\2 \3/p" )";
+	if [[ ! -d "${LOGARCHIVE_BASE}/${YEAR}/${MONTH}/" ]]; then mkdir -p "${LOGARCHIVE_BASE}/${YEAR}/${MONTH}/"; fi
+	if [[    ( $((YEAR)) -ne $((CURRENT_YEAR)) ) || \
+		(( $((YEAR)) -eq $((CURRENT_YEAR)) ) && ( 10#${MONTH} -lt 10#${CURRENT_MONTH} )) ]]; \
+		then
+		if [[ (-f "${LOGFILE}") && $(echo "${LOGFILE}" | grep -e "${YEAR}-${MONTH}-") ]]; then
+			mv "${LOGFILE}" "${LOGARCHIVE_BASE}/${YEAR}/${MONTH}/"
+		fi
+	fi
+done
+
+
+exit 0
+
+
diff --git a/files/usr/local/lib/systemd/system/logs-to-archive.service b/files/usr/local/lib/systemd/system/logs-to-archive.service
new file mode 100644
index 0000000000000000000000000000000000000000..b34ea3a19d0351d2e179cb82547e3dda215f0e27
--- /dev/null
+++ b/files/usr/local/lib/systemd/system/logs-to-archive.service
@@ -0,0 +1,34 @@
+[Unit]
+Description=Cleanup Daemon for Rosetta logs. This will move older Rosetta logs to the log archive that is divided into dated subdirectories.
+After=network.target
+
+[Service]
+ExecStart=/usr/local/bin/logs-to-archive.sh
+ExecReload=/bin/kill -HUP $MAINPID
+KillMode=process
+Restart=on-failure
+Type=simple
+
+### Security features
+# documented at https://www.freedesktop.org/software/systemd/man/systemd.exec.html
+#ProtectSystem=strict
+#ProtectHome=read-only
+#ProtectHostname=true
+#ProtectClock=true
+#ProtectKernelTunables=true
+#ProtectKernelModules=true
+#ProtectKernelLogs=true
+#ProtectControlGroups=true
+#LockPersonality=true
+#MemoryDenyWriteExecute=true
+#RestrictRealtime=true
+#RestrictSUIDSGID=true
+## RemoveIPC=true
+## PrivateMounts=true
+## MountFlags=
+## SystemCallFilter is a Whitelist!!!
+#SystemCallFilter=@aio,@basic-io,@debug,@file-system,@network-io
+#SystemCallErrorNumber=1337
+
+[Install]
+WantedBy=multi-user.target
diff --git a/files/usr/local/lib/systemd/system/logs-to-archive.timer b/files/usr/local/lib/systemd/system/logs-to-archive.timer
new file mode 100644
index 0000000000000000000000000000000000000000..595df9588aef5fc132d9d82dcadd7c9efb29483f
--- /dev/null
+++ b/files/usr/local/lib/systemd/system/logs-to-archive.timer
@@ -0,0 +1,11 @@
+[Unit]
+Description=Cleanup Daemon for Rosetta logs
+
+[Timer]
+Unit=logs-to-archive.service
+Persistent=true
+OnCalendar=monthly
+
+[Install]
+WantedBy=default.target
+
diff --git a/tasks/rosetta/install_log_archival.yml b/tasks/rosetta/install_log_archival.yml
new file mode 100644
index 0000000000000000000000000000000000000000..86225fa8d2711cd12bcd550e716d4f539510b2ac
--- /dev/null
+++ b/tasks/rosetta/install_log_archival.yml
@@ -0,0 +1,24 @@
+---
+- name: install log archival script and systemd units
+  ansible.builtin.copy:
+    src: "{{ item.file }}"
+    dest: "/{{ item.file }}"
+    mode: "{{ item.mode | default('0644') }}"
+    owner: "{{ vault_rosetta_user }}"
+    group: "{{ vault_rosetta_group }}"
+  loop:
+    - file: "usr/local/bin/logs-to-archive.sh"
+      mode: "0755"
+    - file: "usr/local/lib/systemd/system/logs-to-archive.service"
+    - file: "usr/local/lib/systemd/system/logs-to-archive.timer"
+
+- name: start & enable units
+  ansible.builtin.systemd:
+    unit: "logs-to-archive.{{ item.u }}"
+    enabled: true
+    state: "{{ item.s | default(omit) }}"
+    daemon_reload: true
+  loop:
+    - u: "service"
+    - u: "timer"
+      s: "started"
diff --git a/tasks/rosetta/main_rosetta.yml b/tasks/rosetta/main_rosetta.yml
index 2e0eef48bd72e317635a9ece804030bf57eceba2..68354084ce82b3f22ffc58387801c7ecf8cccb5d 100644
--- a/tasks/rosetta/main_rosetta.yml
+++ b/tasks/rosetta/main_rosetta.yml
@@ -37,3 +37,6 @@
 - name: configure Tomcat server
   ansible.builtin.import_tasks: "rosetta/configure_tomcat.yml"
   tags: [rosetta, tomcat, java]
+- name: install log archival for Rosetta logs
+  ansible.builtin.import_tasks: "install_log_archival.yml"
+  tags: [rosetta, log, logs]