Die folgende Installationsanleitung für den Goobi viewer bezieht sich auf Ubuntu Linux 22.04. Sie ist als Schritt für Schritt Anleitung von oben nach unten geschrieben, das bedeutet, dass Einstellungen und Konfigurationen aufeinander aufbauen. Wird die Reihenfolge nicht eingehalten, können unter Umständen bestimmte Befehle fehlschlagen.
Als Domainname wird in dieser Anleitung VIEWER.EXAMPLE.ORG verwendet, dies bitte an den eigenen DNS Namen anpassen.
Für den produktiven Einsatz wird eine virtuelle Maschine mit mindestens 4 CPUs und 8GB RAM empfohlen.
Befehle aus dieser Anleitung werden am besten mit einem Klick auf das entsprechende Icon kopiert. Andernfalls besteht die Gefahr ungewollte Whitespaces mit zu kopieren.
Vorbereitung
Zuerst auf dem Server, auf dem der Goobi viewer installiert werden soll, anmelden und root Rechte erlangen:
ssh VIEWER.EXAMPLE.ORG
sudo -i
Anschließend ein Passwort für die Goobi viewer Datenbank und einen Token generieren und als Variable in der Session ablegen. Dort wird ebenfalls der DNS Name hinterlegt:
Zum Schluss der Vorbereitung muss ein temporäres Verzeichnis für die Installation angelegt und das Goobi viewer Core Config Repository geklont werden. Darin sind für die Installation notwendige Dateien enthalten:
mkdir -p $install
cd $install
git clone https://github.com/intranda/goobi-viewer-core-config.git
Es empfiehlt sich zum jetzigen Zeitpunkt einen DNS Eintrag für den Server gesetzt zu haben.
Variablen und Aliase
Folgende Aliase in die /root/.bash_aliases hinzufügen:
cat << "EOF" >>/root/.bash_aliases
alias cata='journalctl -u tomcat10 -n 1000 -f'
alias ind='tail -n 1000 -f /opt/digiverso/logs/indexer.log'
alias vl='tail -n 1000 -f /opt/digiverso/logs/viewer.log'
EOF
Übernahme der Änderungen in der aktuellen Session:
. /root/.bashrc
Verzeichnisstruktur erstellen
Mit den folgenden Befehlen wird die notwendige Ordnerstruktur erzeugt:
In der /etc/default/tomcat10 den Speicher unter -Xmx dem verfügbaren Maschinenspeicher anpassen, vernünftige Garbage Collector Optionen wählen und urandom für schnelleren Tomcat start nutzen:
patch /etc/default/tomcat10 << "EOF"
@@ -6,11 +6,20 @@
# You may pass JVM startup parameters to Java here. If you run Tomcat with
# Java 8 instead of 9 or newer, add "-XX:+UseG1GC" to select a suitable GC.
# If unset, the default options will be: -Djava.awt.headless=true
-JAVA_OPTS="-Djava.awt.headless=true"
+#JAVA_OPTS="-Djava.awt.headless=true"
# To enable remote debugging uncomment the following line.
# You will then be able to use a Java debugger on port 8000.
#JAVA_OPTS="${JAVA_OPTS} -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n"
+JAVA_OPTS="-Djava.awt.headless=true -Xmx4g -Xms4g"
+JAVA_OPTS="${JAVA_OPTS} -XX:+UseG1GC"
+JAVA_OPTS="${JAVA_OPTS} -XX:+ParallelRefProcEnabled"
+JAVA_OPTS="${JAVA_OPTS} -XX:+DisableExplicitGC"
+JAVA_OPTS="${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom"
+JAVA_OPTS="${JAVA_OPTS} -Dfile.encoding='utf-8'"
+JAVA_OPTS="${JAVA_OPTS} --add-exports=java.desktop/sun.awt.image=ALL-UNNAMED"
+
+UMASK=0022
# Java compiler to use for translating JavaServer Pages (JSPs). You can use all
# compilers that are accepted by Ant's build.compiler property.
@@ -20,4 +29,4 @@
#SECURITY_MANAGER=true
# Whether to compress logfiles older than today's
-#LOGFILE_COMPRESS=1
+LOGFILE_COMPRESS=1
EOF
Weitere Konfigurationen werden in /etc/tomcat10/server.xml vorgenommen. Dabei wird ein HTTP Connector (mit korrektem proxyName) und einen AJP Connector auf localhost eingerichtet. Weiter wird ein Crawler Session Manager Valve aktiviert:
sed -e "s|VIEWER.EXAMPLE.ORG|${VIEWER_HOSTNAME}|g" << "EOF" | patch /etc/tomcat10/server.xml
@@ -65,49 +65,22 @@
AJP Connector: /docs/config/ajp.html
Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
-->
- <Connector port="8080" protocol="HTTP/1.1"
- connectionTimeout="20000"
- redirectPort="8443"
- maxParameterCount="1000"
- />
- <!-- A "Connector" using the shared thread pool-->
- <!--
- <Connector executor="tomcatThreadPool"
- port="8080" protocol="HTTP/1.1"
- connectionTimeout="20000"
- redirectPort="8443"
- maxParameterCount="1000"
- />
- -->
- <!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2
- This connector uses the NIO implementation. The default
- SSLImplementation will depend on the presence of the APR/native
- library and the useOpenSSL attribute of the AprLifecycleListener.
- Either JSSE or OpenSSL style configuration may be used regardless of
- the SSLImplementation selected. JSSE style configuration is used below.
- -->
- <!--
- <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
- maxThreads="150" SSLEnabled="true"
- maxParameterCount="1000"
- >
- <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
- <SSLHostConfig>
- <Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
- type="RSA" />
- </SSLHostConfig>
- </Connector>
- -->
- <!-- Define an AJP 1.3 Connector on port 8009 -->
- <!--
- <Connector protocol="AJP/1.3"
- address="::1"
- port="8009"
- redirectPort="8443"
- maxParameterCount="1000"
- />
- -->
+ <Connector address="127.0.0.1" port="8080" protocol="HTTP/1.1"
+ server=" "
+ connectionTimeout="20000"
+ maxThreads="400"
+ URIEncoding="UTF-8"
+ enableLookups="false"
+ disableUploadTimeout="true"
+ proxyName="VIEWER.EXAMPLE.ORG"
+ proxyPort="80" />
+
+ <Connector address="127.0.0.1" port="8009" protocol="AJP/1.3"
+ secretRequired="false"
+ connectionTimeout="20000"
+ maxThreads="400"
+ URIEncoding="UTF-8" />
<!-- An Engine represents the entry point (within Catalina) that processes
every request. The Engine implementation for Tomcat stand alone
@@ -150,9 +123,14 @@
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
+ <!--
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
+ -->
+ <Valve className="org.apache.catalina.valves.CrawlerSessionManagerValve"
+ crawlerUserAgents=".*[bB]ot.*|.*Yahoo! Slurp.*|.*Feedfetcher-Google.*|.*Apache-HttpClient.*|.*[Ss]pider.*|.*[Cc]rawler.*|.*nagios.*|.*Yandex.*|.*facebookexternalhit.*|.*bytedance.com.*|.*Turnitin.*|.*GoogleOther.*|.*python-requests.*|.*check_http.*"
+ sessionInactiveInterval="60"/>
</Host>
</Engine>
EOF
Die Sessionpersistenz in der /etc/tomcat9/context.xml deaktivieren, indem der folgende Patch ausgeführt wird:
patch /etc/tomcat10/context.xml << "EOF"
@@ -28,4 +28,7 @@
<!--
<Manager pathname="SESSIONS.ser" />
-->
+
+ <!-- Set mode for the JSESSONID cookie. Google authentication needs "lax" -->
+ <CookieProcessor sameSiteCookies="strict" />
</Context>
EOF
Apache
Apache muss eingerichtet werden, um den Viewer extern zur Verfügung zu stellen. Dafür die folgenden Module aktivieren:
Die folgende Datei nach /etc/apache2/sites-available/${VIEWER_HOSTNAME}.conf legen:
sed -e "s|VIEWER.EXAMPLE.ORG|${VIEWER_HOSTNAME}|g" << "EOF" >/etc/apache2/sites-available/${VIEWER_HOSTNAME}.conf
<VirtualHost *:80>
ServerAdmin support@intranda.com
ServerName VIEWER.EXAMPLE.ORG
DocumentRoot /var/www
## make sure rewrite is enabled
RewriteEngine On
## search engines: do not follow certain urls
RewriteCond %{HTTP_USER_AGENT} ^.*bot.*$ [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*Yandex.*$ [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*spider.*$ [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*rawler.*$ [NC]
ReWriteRule ^(.*);jsessionid=[A-Za-z0-9]+(.*)$ $1$2 [L,R=301]
RewriteCond %{HTTP_USER_AGENT} ^.*bot.*$ [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*Yandex.*$ [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*spider.*$ [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*rawler.*$ [NC]
ReWriteRule ^(.*)viewer/!(.*)$ $1viewer/$2 [L,R=301]
RewriteCond %{HTTP_USER_AGENT} ^.*bot.*$ [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*Yandex.*$ [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*spider.*$ [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*rawler.*$ [NC]
ReWriteRule ^(.*)/[Ll][Oo][Gg]_(.*)$ $1/ [L,R=301]
## compress output
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/plain text/html text/xml
AddOutputFilterByType DEFLATE text/css text/javascript
AddOutputFilterByType DEFLATE application/xml application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript application/x-javascript
AddOutputFilterByType DEFLATE application/json
</IfModule>
## general proxy settings
ProxyPreserveHost On
<Proxy *>
Require local
</Proxy>
## CORS for IIIF
Header set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "GET, OPTIONS"
Header always set Access-Control-Max-Age "600"
Header always set Access-Control-Allow-Headers "Authorization, Content-Type"
Header always set Access-Control-Expose-Headers "Content-Security-Policy, Location"
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
# make sure ETag headers are forwarded correctly
# Post Apache 2.4 have a look at
# https://httpd.apache.org/docs/trunk/mod/mod_deflate.html#deflatealteretag
RequestHeader edit "If-None-Match" '(.*)-gzip"$' '$1", $1-gzip"'
## Enable WebSockets to check concurrent access
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule /?(.*) ws://localhost:8080/$1 [P,L]
## Security
# If set to 'none' the Matomo iFrame does not work anymore
Header set Content-Security-Policy "frame-ancestors 'self';"
Header always append X-Frame-Options DENY
Header always set X-XSS-Protection "1; mode=block"
Header always set X-Content-Type-Options nosniff
## Viewer
redirect 301 /index.html http://VIEWER.EXAMPLE.ORG/viewer/
redirect 301 /viewer http://VIEWER.EXAMPLE.ORG/viewer/
ProxyPassMatch ^/viewer/(.*)$ ajp://localhost:8009/viewer/$1 retry=0
<LocationMatch ^/viewer/(.*)$>
ProxyPassReverse ajp://localhost:8009/viewer/$1
<IfModule mod_expires.c>
ExpiresActive on
ExpiresByType image/jpg "access plus 1 months"
ExpiresByType image/gif "access plus 1 months"
ExpiresByType image/jpeg "access plus 1 months"
ExpiresByType image/png "access plus 1 months"
ExpiresByType font/ttf "access plus 1 year"
ExpiresByType application/x-font-woff "access plus 1 year"
ExpiresByType application/vnd.ms-fontobject "access plus 1 year"
</IfModule>
Require all granted
</LocationMatch>
## solr
redirect 301 /solr http://VIEWER.EXAMPLE.ORG/solr/
<Location /solr/>
Require local
ProxyPass http://localhost:8983/solr/ retry=0
ProxyPassReverse http://localhost:8983/solr/
</Location>
## logging
CustomLog /var/log/apache2/VIEWER.EXAMPLE.ORG_access.log combined
ErrorLog /var/log/apache2/VIEWER.EXAMPLE.ORG_error.log
# Possible values include: debug, info, notice, warn, error, crit, alert, emerg.
LogLevel warn
</VirtualHost>
EOF
Dann ein wenig Hardening des Apaches für den Produktivbetrieb:
patch /etc/apache2/conf-available/security.conf << "EOF"
@@ -22,7 +22,7 @@
# Set to one of: Full | OS | Minimal | Minor | Major | Prod
# where Full conveys the most information, and Prod the least.
#ServerTokens Minimal
-ServerTokens OS
+ServerTokens Prod
#ServerTokens Full
#
@@ -33,7 +33,7 @@
# Set to "EMail" to also include a mailto: link to the ServerAdmin.
# Set to one of: On | Off | EMail
#ServerSignature Off
-ServerSignature On
+ServerSignature Off
#
# Allow TRACE method
EOF
Nun den Goobi viewer vhost aktivieren, den Default vhost deaktivieren und den Apache Webserver neu starten:
Wird UFW benutzt muss Apache freigeschaltet werden:
ufw allow Apache\ Full
MySQL / MariaDB
Der Goobi viewer benötigt eine Datenbank und einen eigenen Nutzer. Dies wird mit dem folgenden Befehl angelegt:
mysql -e "CREATE DATABASE viewer;
CREATE USER 'viewer'@'localhost' IDENTIFIED BY '$PW_SQL_VIEWER';
GRANT ALL PRIVILEGES ON viewer.* TO 'viewer'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;"
Das Datenbankschema wird beim ersten Start der Applikation automatisch erstellt.
NFS
Dieser Punkt ist nur relevant, wenn Goobi workflow ebenfalls installiert ist/wird, und das nicht auf der gleichen Maschine erfolgt.
Dann muss der Ordner /opt/digiverso/viewer zu dem Goobi workflow Server exportiert werden. Hierfür wird NFS genutzt. Die Anpassungen dafür sind hier:
Im folgenden ist die Installation der benötigten Komponenten beschrieben.
Apache Solr
Solr herunterladen und das Installationsskript entpacken:
cd $install
wget https://archive.apache.org/dist/solr/solr/9.8.0/solr-9.8.0.tgz
tar -xzf solr-9.8.0.tgz solr-9.8.0/bin/install_solr_service.sh --strip-components=2
Nun den Ordner /opt/digiverso/solr anlegen und dorthin installieren:
Um Streaming Expressions zu nutzen wird Solr nicht im Standalone, sondern in der SolrCloud Variante installiert. Allerdings nutzen wir nur einen Node. Für die Konfiguration wird Zookeeper verwendet:
Dafür sorgen, dass Zookeeper nur noch auf localhost lauscht:
patch /etc/zookeeper/conf/zoo.cfg << "EOF"
@@ -9,9 +9,10 @@
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
-dataDir=/tmp/zookeeper
+dataDir=/var/lib/zookeeper
# the port at which the clients will connect
clientPort=2181
+clientPortAddress=127.0.0.1
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
EOF
rm /var/lib/zookeeper/myid
systemctl restart zookeeper
Dann die Installation Solr bekannt machen sowie den Speicher, die Garbage Collector Optionen und das Log Level anpassen. Außerdem soll ebenfalls der Solr nur auf localhost lauschen:
patch /etc/default/solr.in.sh << "EOF"
@@ -32,7 +32,7 @@
#SOLR_START_WAIT="$SOLR_STOP_WAIT"
# Increase Java Heap as needed to support your indexing / query needs
-#SOLR_HEAP="512m"
+SOLR_HEAP="2048m"
# Expert: If you want finer control over memory options, specify them directly
# Comment out SOLR_HEAP if you are using this though, that takes precedence
@@ -50,25 +50,19 @@
# -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime"
# These GC settings have shown to work well for a number of common Solr workloads
-#GC_TUNE=" \
-#-XX:+ExplicitGCInvokesConcurrent \
-#-XX:SurvivorRatio=4 \
-#-XX:TargetSurvivorRatio=90 \
-#-XX:MaxTenuringThreshold=8 \
-#-XX:+UseConcMarkSweepGC \
-#-XX:ConcGCThreads=4 -XX:ParallelGCThreads=4 \
-#-XX:+CMSScavengeBeforeRemark \
-#-XX:PretenureSizeThreshold=64m \
-#-XX:+UseCMSInitiatingOccupancyOnly \
-#-XX:CMSInitiatingOccupancyFraction=50 \
-#-XX:CMSMaxAbortablePrecleanTime=6000 \
-#-XX:+CMSParallelRemarkEnabled \
-#-XX:+ParallelRefProcEnabled etc.
+GC_TUNE=" \
+-XX:+ExplicitGCInvokesConcurrent \
+-XX:SurvivorRatio=4 \
+-XX:TargetSurvivorRatio=90 \
+-XX:MaxTenuringThreshold=8 \
+-XX:ConcGCThreads=4 -XX:ParallelGCThreads=4 \
+-XX:PretenureSizeThreshold=64m \
+-XX:+ParallelRefProcEnabled"
# Set the ZooKeeper connection string if using an external ZooKeeper ensemble
# e.g. host1:2181,host2:2181/chroot
# Leave empty if not using SolrCloud
-#ZK_HOST=""
+ZK_HOST="127.0.0.1:2181"
# Set to true if your ZK host has a chroot path, and you want to create it automatically.
#ZK_CREATE_CHROOT=true
@@ -129,7 +123,7 @@
# Changes the logging level. Valid values: ALL, TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF. Default is INFO
# This is an alternative to changing the rootLogger in log4j2.xml
-#SOLR_LOG_LEVEL=INFO
+SOLR_LOG_LEVEL=ERROR
# Location where Solr should write logs to. Absolute or relative to solr start dir
#SOLR_LOGS_DIR=logs
@@ -293,7 +287,7 @@
# SOLR_OPTS="$SOLR_OPTS -Dlog4j2.formatMsgNoLookups=true"
# The bundled plugins in the "modules" folder can easily be enabled as a comma-separated list in SOLR_MODULES variable
-# SOLR_MODULES=extraction,ltr
+SOLR_MODULES=analysis-extras
# Configure the default replica placement plugin to use if one is not configured in cluster properties
# See https://solr.apache.org/guide/solr/latest/configuration-guide/replica-placement-plugins.html for details
EOF
Außerdem sicherstellen, dass Solr erst nach dem Zookeeper gestartet wird:
Zuerst wird die Applikation heruntergeladen. Danach werden die benötigten Dateien nach /opt/digiverso/indexer/ kopiert, der Tomcat Port kontrolliert und gegebenenfalls C: durch /opt ersetzt. Zum Schluss wird die systemd Service Unit aktiviert:
Für regelmäßige Aufgaben müssen Cronjobs eingerichtet werden:
sed -e "s|VIEWER.EXAMPLE.ORG|${VIEWER_HOSTNAME}|g" -e "s|TOKEN|${TOKEN}|g" << "EOF" >/etc/cron.d/intranda-goobiviewer
PATH=/usr/bin:/bin:/usr/sbin/
MAILTO=admin@intranda.com
#
# Regular cron jobs for the Goobi viewer
#
## Optimize the Solr search index once a month
@monthly root curl -s 'http://localhost:8983/solr/collection1/update?optimize=true&waitFlush=false'
EOF
config_viewer.xml
In der lokalen config_viewer.xml müssen verschiedene Einstellungen hinterlegt werden, hierbei müssen Domain und gegebenenfalls das Protokoll angepasst werden:
Der Goobi viewer verfügt über ein Backend. Mit dem folgenden Kommando wird ein Testaccount mit dem Benutzernamen goobi@intranda.com und dem anfangs festgelegten Passwort in die Datenbank eingefügt:
VIEWER_USERPASS_HASH=$(python3 -c "from passlib.hash import bcrypt; print(bcrypt.using(rounds=10, ident='2a').hash('${VIEWER_USERPASS}'))")
mysql viewer -e "INSERT INTO users (active,email,password_hash,score,superuser) VALUES (1,'${VIEWER_USERNAME}','${VIEWER_USERPASS_HASH}',0,1);"