3 Setup instructions
This section contains instructions for setting up a new Oskari instance. First a PostgreSQL database with PostGIS extension is set up, then the actual Oskari instance with related programs is downloaded and installed. These instruction use usernames, passwords and other values that you should change for production, but are ones that the Oskari downloadable example installation uses as defaults and pre-configured settings. For your first install you should probably use the defaults and see that you can get the server running. After that you can start over by dropping the database and start tinkering with the configurations to use your preferred credentials and other environment specific changes.
This manual focuses on Oskari and gives you the basic guidance to the related software/libraries which should be enough to get you through the setup process. If you encounter issues with PostgreSQL or other Oskari-related libraries, please refer to their respective manuals.
The diagram below shows the components that are commonly used in Oskari installations.
C4Deployment Person(user, "User", "") Boundary(service, "Oskari-based service", "") { Boundary(frontend, "Web server", "nginx/httpd"){ Component(sample-app, "sample-application", "Javascript") } Boundary(server, "Servlet container", "tomcat/jetty") { Component(sample-server, "sample-server-extension", "Java") } Boundary(db, "Databases", "") { ContainerDb(postgres, "PostgreSQL", "PostGIS/SQL", "Application config and user data") ContainerDb(redis, "Redis", "", "Caching") } } System_Ext(sdi, "OGC and other APIs", "External services") Rel(user, sample-app, "", "") Rel(sample-app, sample-server, "", "") Rel(sample-server, postgres, "", "") Rel(sample-server, redis, "", "") Rel(sample-server, sdi, "", "") Rel(user, sdi, "", "")
3.1 Setup database
This document describes how to set up a single database for the oskari-server component.
The standalone Oskari server depends on the availability of PostgreSQL with PostGIS extension for serving content and authenticating users.
3.1.1 Database requirements:
The following components are assumed pre-installed:
- PostgreSQL 11+ (Known to work with 11, 12, 14 mainly affected by the version of FlywayDB-dependency that is used by
oskari-server
. Developed using 14.) - PostGIS (Developed using 3)
3.1.2 Steps to create the database
Install a supported version of PostgreSQL and PostGIS on your environment.
The default configurations assume PostgreSQL is installed on localhost
with the default PostgreSQL port (5432
).
This is configurable in oskari-ext.properties
file (found under oskari-server/lib/
folder in the downloadable file).
Create an empty database with PostGIS extension
The default configurations assume the database name is oskaridb
(configurable in oskari-ext.properties
file).
Run the create database SQL in for example psql or pgAdmin (see if they were installed in the PostgreSQL installation package):
CREATE DATABASE oskaridb
WITH OWNER = postgres
ENCODING = 'UTF8'
TABLESPACE = pg_default
CONNECTION LIMIT = -1;
Connect to the database with \c oskaridb
in psql or by opening the query tool on pgAdmin or similar for the oskaridb
database.
Run this SQL on the database to add the PostGIS extension:
CREATE EXTENSION postgis;
Setup a database user for oskaridb
Run these commands to create default user with all privileges
CREATE USER oskari WITH PASSWORD 'oskari';
GRANT ALL PRIVILEGES ON DATABASE oskaridb TO oskari;
The preconfigured database user in Oskari example application is oskari
with the password oskari
(configurable in oskari-ext.properties
file).
Some versions of PostgreSQL might also need you to run:
GRANT ALL PRIVILEGES ON SCHEMA public TO oskari;
If you see error messages like this when starting the server: Message: ERROR: permission denied for schema public
you need to add privileges for the schema as well.
For production environments you can define lesser privileges for the database user, however the migration scripts (run on version updates) can create, drop or alter tables on the database so you will need to allow these. It is also possible to run the migrations required on server updates with a user that has more privileges while using another user with lesser prileges for operational use.
Application initialization and database content
The empty database will be populated with table structure and example data when the application server is started for the first time using automatic migrations. The database migrations are split into modules. The core module creates and migrates the main database tables used by Oskari. Changes to these need to be done on the oskari-server repository itself and usually can't be skipped by the application.
The example configuration includes a migration module named app
(in oskari-ext.properties
) that will populate initial example data for the demo application to get a nice unboxing experience. Changing or replacing the app
module is the intended way of customizing any application specific migrations and possible initial data and/or users. These application specific migrations also create the default users and their credentials that can be used to login to the example application. These you must change or remove when creating your own Oskari-based application.
Note that migrations are run only once so making changes to existing migration files and restarting the application server requires an empty database for migrations to be run again (or removing related rows on the migration status database tables). However the migrations follow versioning through naming so you can add migrations to modify an existing database by naming the migrations in a certain way.
The next step after having the database ready is installing the application that runs these migrations. If you want to skip way ahead and learn how to customize Oskari including populating the database with your own content instead of example content see:
3.2 Setup application server
This section contains instructions on setting up a Java application server for Oskari using the download package with Tomcat and pre-installed/configured Oskari
After completing this section you will have the Oskari-based example application running, including:
- Oskari-frontend based sample-application (https://github.com/oskariorg/sample-application)
- Oskari-server based sample webapp (https://github.com/oskariorg/sample-server-extension)
Requirements
The following are required for setting up Jetty.
- JDK 17 (Java Development Kit)
- Database available: Instructions for setting up database
Setting up Tomcat
Follow the steps below to get Tomcat properly set up.
1) Download the Oskari example application
2) Unpack the zip file to selected location
The zip includes:
- Readme.md
- licence folder
- oskari-map.war as prebuilt server application
- sample-application folder with the prebuilt frontend application code
- apache-tomcat-10.1.39 (referred as
{tomcat.home}
) - oskari-server folder (referred as
{tomcat.base}
)
3) Configure the database properties (host/credentials) by editing {tomcat.base}/lib/oskari-ext.properties
db.url=jdbc:postgresql://[host]:[port]/[dbname]
db.username=[user]
db.password=[passwd]
4) Startup the Tomcat
By running the command (in {tomcat.base}
):
server.bat start
for Windows ORserver.sh start
for *nix-based OS (Ubuntu, MacOS, Windows WSL etc)
Note that it's important where you run the command/what is the working directory so run the command in the oskari-server
folder. Otherwise folder references in those scripts might not work as expected.
The scripts are for convenience only, you could download Tomcat from their site and use that to run Oskari. Separating {tomcat.base}
and {tomcat.home}
is useful if you want to use Tomcat binaries as shared library
(the {tomcat.home}
folder) and have multiple different Oskari-based applications with their own config and code on their own Tomcat instances. You can add parallel instances by just making copies of the {tomcat.base}
and changing their configurations.
The main configurations you might want to take a look at under {tomcat.base}
when setting up a different setup are:
- eveything under
lib/*
with the most important file beinglib/oskari-ext.properties
. This is the main configuration file and is searched from the Java classpath on server startup. - context XML-files under
conf/Catalina/localhost/*.xml
- log files are generated under the
logs
folder
The zip has sample-application
and oskari-map.war
as the actual applications that are served from Tomcat. These are referenced in the conf/Catalina/localhost/*.xml
files. If you want to have the files somewhere else, you can modify the XML-files to use some other location.
5) After Tomcat is up and running open a browser with URL
http://localhost:8080
You can login as:
- user with username "user" and password "user"
- admin with username "admin" and password "oskari"
Note! These default users are introduced in the database migration module for the example application (sample-server-extension) and publicly advertized on the sample-info bundle in the sample-application (frontend repository). You should change/remove these for any applications you create based on the example setup.
Advanced configuration
For further configuration check out Server configuration
3.3 Build customized server-side application
This section describes how to replace the prebuilt server side webapp with your own version. This is the intended way of customizing Oskari-based applications.
3.3.1 Server requirements
The following items are required for the development process:
- JDK 17
- Maven 3+ (developed using 3.6.3)
- Git client (optional)
- GitHub account (optional)
You will need an environment to run the code in as described on Setup application server
Feel free to use the git conventions used in Oskari development with your own customizations, but it's your app so you can make your own choices.
3.3.2 Create your server application repository
You can use our sample-server-extension
template for creating a repository that will have your application customizations under your own GitHub user/organization:
https://github.com/new?template_name=sample-server-extension&template_owner=oskariorg
Clone the repository to your own computer with git. You can use any program you are comfortable with to work with git, but on command line you can run:
git clone https://github.com/oskariorg/sample-server-extension.git
Replace oskariorg
with your own username/organization name and sample-server-extension
if you changed the repository name for your app.
For simple testing you can also just clone our template repository for tinkering, but BEWARE the template repository is intended to be a starting point and it will be updated in ways where the migrations and initial content will be modified in place (skipping the migration history like is usually done for maintained apps). This means that going forward you can't simply merge released changes from the template repository to your application repository using git so it's best to create a copy and not a fork of the sample-server-extension for your own app.
If you don't use git you can also just download the repository code as zip from GitHub.
3.3.3 Build your version of the server application
Once you have the server application repository cloned (or downloaded and unzipped) you can use Maven to build your own version of the oskari-map.war
.
Go to the root folder of the repository (cd sample-server-extension
) and run the Maven command:
mvn clean install
This will create the oskari-map.war
file under webapp-map/target
.
You can replace the oskari-map.war
from the Oskari download package with this newly created file and restart the server.
3.3.4 Simple server modifications
These are some easy to test modifications to see that your server application has changed:
- JSP-files under
webapp-map/src/main/webapp/WEB-INF/jsp
has the base HTML in them. You can simply change the value of<title>
tag for example. - JSON-files under
app-resources/src/main/resources/json/apps
select the functionalities (Oskari "bundles") that will be used on the application (Note! changing these will require an empty database to see changes) - Flyway migrations under
app-resources/src/main/resources/flyway/app
andapp-resources/src/main/java/flyway/app
(Note! changing these will require an empty database to see changes)
Note! When you change something in the code, you need to recompile/build a new version of oskari-map.war
and deploy the new version on the server.
If you change anything on the initial data/migrations you need to drop the database and create a new empty one. To migrate the content from it's initial state you can add new migrations that will be run on an existing database, but modifying ones that have already been executed on the database will not be rerun on a non-empty database.
3.3.5 WAR-file location
If you want to use the war-file from another location you can change the reference to the war-file. This can be changed in oskari-server/conf/Catalina/localhost/ROOT.xml
(https://github.com/oskariorg/sample-configs/blob/master/tomcat-10/oskari-server/conf/Catalina/localhost/ROOT.xml) by changing the value of docBase
:
<Context docBase="../../oskari-map.war" reloadable="true" />
For development it's easiest to have it reference the {your.git.repo.root}/webapp-map/target/oskari-map.war
directly so it will be redeployed as soon as you compile a new version without need to copy the file around.
3.4 Build customized frontend application
This section describes how to replace the prebuilt frontend application with your own version. This is the intended way of customizing Oskari-based applications.
3.4.1 Frontend requirements
The following items are required for the development process:
- NodeJS (developed using 18+)
- Git client (optional)
- GitHub account (optional)
You will need an environment to run the code in as described on Setup application server
Feel free to use the git conventions used in Oskari development with your own customizations, but it's your app so you can make your own choices.
3.4.2 Create your frontend application repository
You can use our sample-application
template for creating a repository that will have your application customizations under your own GitHub user/organization:
https://github.com/new?template_name=sample-application&template_owner=oskariorg
Clone the repository to your own computer with git. You can use any program you are comfortable with to work with git, but on command line you can run:
git clone https://github.com/oskariorg/sample-application.git
Replace oskariorg
with your own username/organization name and sample-application
if you changed the repository name for your app.
For simple testing you can also just clone our template repository for tinkering, replacing the existing sample-application
folder with your cloned repository.
If you don't use git you can also just download the repository code as zip from GitHub.
Note! The sample application, including its source code and build, is available in the sample-application
folder within the Oskari download package. The frontend application builds are generated in the dist
folder under the sample-application
and the prebuilt version is included in the download zip file.
3.4.3 Build your version of the frontend application
Modern web applications are developed using JavaScript syntax that is not fully supported by older browsers and the code needs to be processed before it can be used by the end-user browsers. This step also includes bundling and minifying the code so it's more compact for consumption than the human-friendly version that is used for development. This will reduce the startup time for the end-user dramatically.
- Go to the root folder of the repository (
cd sample-application
) - On the first time (or after you have updated Oskari version) run
npm install
to install dependencies - Run the npm command to generate new build product:
npm run build
This creates a new version folder under sample-application/dist/
. The version is named after version
in the package.json
file (having package.json version as 1.0
will generate sample-application/dist/1.0/
).
3.4.4 Frontend location and version
If you want to use another name than sample-application you can change the folder in which the application server looks for the frontend.
For example you might want to use some other name for the repository that holds your version of the frontend application.
This can be changed in oskari-server/conf/Catalina/localhost/Oskari.xml
(https://github.com/oskariorg/sample-configs/blob/master/tomcat-10/oskari-server/conf/Catalina/localhost/Oskari.xml) by changing the value of docBase
:
<Context docBase="../../sample-application" reloadable="true" />
Note that the frontend code doesn't need to be server through the application server and could be served with servers like nginx or Apache HTTPD.
However the server does have a configuration which version of the frontend it uses on oskari-server/lib/oskari-ext.properties
https://github.com/oskariorg/sample-configs/blob/master/tomcat-10/oskari-server/lib/oskari-ext.properties:
oskari.client.version=dist/2.0.0
Where the version in oskari-ext.properties
must match the folder where the frontend app build product was generated to (package.json
version).
3.4.5 Simple frontend modifications and dev-server
An easy way of seeing a Hello world
type of modification is adding something like console.log("Hello world")
in the start()
function of the SampleInfoBundleInstance.js.
Unfortunately any change to the frontend requires a build to be run to see the changes updated. To help with this the frontend offers the option to use Webpack dev-server by running npm run start
instead of npm run build
.
The dev-server starts serving the frontend files from http://localhost:8081 and requires the server to respond from http://localhost:8080. It also requires that the server is configured to use this client version in oskari-server/lib/oskari-ext.properties
(as opposed to version from package.json):
oskari.client.version=dist/devapp
Note! Changes to oskari-ext.properties
requires the server to restart to take effect.
The dev-server provides the changed version after automatic page reloading so it's much more convenient to use for development than running the build after every change, but it's not perfect so if you don't see your changes you might need to restart the dev-server during development.
Frontend build details
The build scripts work by reading a main.js
file that links all the functionality/bundles you want to use in your application together and should match the appsetup (bundle collection) used on the website you are creating including any dynamic (role-based) bundles that are added on the fly. So basically all the bundles you want to use in that application. Here's an example for the basic geoportal appsetup and for an embedded map. These are both processed when running npm run build
. Note that linking the bundles to be part of the frontend application in main.js
only includes the functionalities that CAN be used in an application. The server/database configurations dictates which of the functionalitise that have been included is actually started for a given application. This allows for example admin-bundles to be shown only when the user has the admin role, but also allows reusing the same frontend application to show different kinds of applications based on the database configuration. For example using the same embedded
application for all different kinds of published maps where end-users can select through a browser-based UI which functionalities will be included in any given embedded map.
If you take a look at the package.json script for build you can see that the parameter --env appdef=applications
is used to point the build to search for main.js files under the applications
folder. You can change this in your own app as you wish.
The best point to start customizing your app is changing the main.js
file under the sample geoportal
application to only include the bundles that you are using. This reduces the amount of code the end-user needs to load. You can also safely remove the 3D applications if you don't need them. The embedded
application (code for published maps) usually stays more or less the same and the geoportal
one is usually customized based on requirements.
When changing main.js
to include application specific bundles and/or customizing the application you need to run npm run build
again to create new build product under the dist
folder. You will also need to do this when updating the new version of Oskari or after changing any application specific code/bundles you want to use.
3.5 Updating Oskari version
This section guides you through updating your Oskari instance.
We are updating the frontend and server versions at the same time and for the best compatibility it's best to use same version in both. Hotfix/patch versions might not always match but with version major.minor.patch
the major and minor versions should match.
Before updating, the following links are recommended to at least skim through:
3.5.1 Migration and release notes
In most cases updating Oskari version means:
- updating the version of Oskari dependency for the frontend and server and
- building new versions of your frontend app/server
Sometimes there are additional things that need to be done when updating. These are documented on the Migration Guide in oskari-server repository.
There can be also application spesific things that need to be taken into account when updating. For example, your application code might not compile after updating if you have changed some class in oskari-server that you are using directly in your app.
You should also at least skim through the Release notes for both the server and the frontend to see if there is something that might affect your app. There might be, for example, a new implementation of a bundle/functionality that you want to use instead of the old one.
It's also a good idea to see any PRs/changes for the sample application to see if there are things that you can streamline/change in your application for the newer version:
- https://github.com/oskariorg/sample-application
- https://github.com/oskariorg/sample-server-extension
Note! The idea is NOT to you use the sample-application/server directly but to use it as a template to create your own app/server. For example the database migrations in server-template assume they are run on an empty database and might not work properly if copied directly to your server code. We change the sample migrations between versions to make the most sense as simple examples for the latest version while actual apps (copies of sample-server) should work to migrate the existing database of the app.
3.5.2 Updating the server
Updating an Oskari-powered server that is based on the sample-server-extension template is done by updating the value of oskari.version
property in pom.xml file:
<properties>
<oskari.version>1.0.0</oskari.version>
...
</properties>
To the new version:
<properties>
<oskari.version>1.0.1</oskari.version>
...
</properties>
After this run mvn clean install
to generate a new oskari-map.war
under {your.server.repository.root}/webapp-map/target
. Replace the oskari-map.war
with the new one as described on Build customized server-side application.
3.5.3 Updating the frontend
Updating an Oskari application that is based on the sample-application template is fairly simple as well. For the frontend the oskari-frontend
(and possible oskari-frontend-contrib
) dependency is updated by changing the version number in package.json file from the current version in the app:
"dependencies": {
"oskari-frontend": "https://git@github.com/oskariorg/oskari-frontend.git#1.0.0"
},
To the new version:
"dependencies": {
"oskari-frontend": "https://git@github.com/oskariorg/oskari-frontend.git#1.0.1"
},
When updating Oskari version, feel free to change the application version as well in package.json of your application to signal that the application has been updated.
After this you need to run npm install
to install any new/changed libraries and npm run build
to generate a new build under {your.server.repository.root}/dist/[version on package.json]
as described on Build customized frontend application.
Finally, remember to update the newly built frontend version to oskari-ext.properties
under oskari-server/lib
:
oskari.client.version=dist/[version from your package.json]
3.6 Advanced configuration
The section contains advanced setup and configuration instructions which users usually do not need to worry about.
3.6.1 Server configuration
Default configuration
The preconfigured Tomcat uses these defaults. These can be changed by modifying {tomcat.base}/lib/oskari-ext.properties
.
Redis:
- running on localhost
- default port (6379)
Database (Postgres with PostGIS extension):
- db URL: localhost in default port (5432)
- db name: oskaridb
- db user: oskari/oskari
Oskari (provided in download example):
Custom configurations
1) Removing the unnecessary parts
The download example uses prebuilt frontend application in the sample-application
folder and prebuilt server application as oskari-map.war
. These have repositories that you can use as templates to create your own copies of them:
- https://github.com/oskariorg/sample-server-extension
- https://github.com/oskariorg/sample-application
For modifying what the application initializes for the database content and changing functionalities that you want to include on your application, you will need to create your own modifications and these templates provides an easy way of getting started. One of the easiest way of modifying your application is adding/removing code to/from the application repository, include more dependencies or drop ones that you don't need (like statistical-data related ones if you don't want to use that Oskari functionality in your application).
Similarly, you will need to add/remove references to the functionalities on the frontend application. This is usually done on the sample-application/applications/geoportal/main.js
file by importing new functionalities or removing unused ones. The frontend application desides what code is included for the frontend. However, it is the database that actually tracks what functionalities are shown on the user interface. Functionalities are packaged as "bundles" in Oskari terms. To use a bundle, the frontend must include it for the frontend build AND the server/database must reference the bundle so it is started by the frontend. You can have bundles that are started based on user roles so not all bundles that are included by the frontend will be shown for all users (for example admin functionalities).
The different kinds of views that the user can see are saved as "appsetup" on the database. An appsetup has some metadata like which JSP-file is used for the appsetup, which frontend application (geoportal/embedded/custom one) is shown and it can have a UI theme to select colors etc for that specific views. A usual setup is having the default appsetup that is shown for all users like a geoportal. Users can use the publisher functionality in Oskari to create new appsetups as they publish maps or even just saving a customized geoportal appsetup.
Appsetups have a list of "bundles" that are linked to an appsetup. This list determines which functionalities are used by that appsetup. Related database tables are:
- oskari_appsetup
- oskari_appsetup_bundles
2) Editing article content
- User guide: edit the file in
{tomcat.base}/lib/articlesByTag/userguide.html
- Publisher terms of use: edit the file in
{tomcat.base}/lib/articlesByTag/termsofuse__mappublication__en.html
3) Changing the default port**
Change {tomcat.base}/conf/server.xml
where ever 8080
is referenced in here
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8080"
maxParameterCount="1000"
relaxedQueryChars="|"
scheme="https" secure="true"
parseBodyMethods="POST,PUT"
/>
4) Proxy settings
If you need a proxy to access internet you can pass the configuration in the application server command line start commaned with:
-Dhttp.proxyHost=
-Dhttp.proxyPort=
-Dhttp.nonProxyHosts=
-Dhttps.proxyHost=
-Dhttps.proxyPort=
-Dhttps.nonProxyHosts=
In the Oskari download the variables.sh
holds placeholder for configuring proxy settings
5) Database url/name/user/pass are changed
{tomcat.base}/lib/oskari-ext.properties
needs to be updated
db.url=jdbc:postgresql://[host]:[port]/[dbname]
db.username=[user]
db.password=[passwd]
5) Using external Redis
{tomcat.base}/lib/oskari-ext.properties
needs to be updated
redis.hostname=localhost
redis.port=6379
redis.pool.size=10
3.6.2 Setup Redis for Oskari (Optional)
Redis is used for caching data for example from statistical datasources to provide a cleaner user experience for statistical map functionalities (optional part of oskari-map
webapp). It is also used in clustered environment (when you have multiple instances running an Oskari-based server) for session management (servers see sessions initiated by the other nodes) and cluster messaging like flushing caches from all nodes when something is updated on one node.
1) Get Redis
Install binaries from http://redis.io/ or from your platforms package repository.
2) Install
And startup redis-server
. The default port Redis listens to is 6379
.
3) Configure Oskari (Optional)
Oskari expects Redis to be found in the default port (6379) on the same server as Oskari ("localhost"). If you have it running on another host/port you need to change the oskari-ext.properties
:
redis.hostname = localhost
redis.port = 6379
# # Credentials
# redis.user = (optional)
# redis.password = (optional)
# # Timeout configuration is milliseconds
# redis.timeout.connect = 2000
# redis.ssl = false
# redis.pool.size = 30
# # BlockWhenExhausted setting
# redis.blockExhausted = false
The commented ones are optional and depend on your environment. The values are the defaults (user/pass defaults are not defined).
3.6.3 Configuring a reverse proxy (Optional)
This guide gives an example for configuring a reverse proxy in front of an Oskari-based application. You can use software such as nginx or Apache httpd or similar for this and use the chosen server to serve the static frontend application files as well. The server can function as a load balancer or just as a dummy proxy that decides to respond with static files for the frontend application or proxy the request to the underlying application server.
Using a reverse proxy is not required for development, but is recommended for production use
C4Deployment Person(user, "User", "") Boundary(service, "Oskari-based service", "") { Boundary(frontend, "Web server", "nginx/httpd") { Component(sample-app, "sample-application", "Javascript") } Boundary(server, "Servlet container", "tomcat/jetty") { Component(sample-server_1, "sample-server-extension", "Java") } Boundary(server2, "Servlet container", "tomcat/jetty") { Component(sample-server_2, "sample-server-extension", "Java") } Boundary(db, "Databases", "") { ContainerDb(postgres, "PostgreSQL", "PostGIS/SQL", "Application config and user data") ContainerDb(redis, "Redis", "", "Caching/Cluster messaging") } } Rel(user, sample-app, "", "") Rel(sample-app, sample-server_1, "", "") Rel(sample-app, sample-server_2, "", "") Rel(sample-server_1, postgres, "", "") Rel(sample-server_2, postgres, "", "") Rel(sample-server_1, redis, "", "") Rel(sample-server_2, redis, "", "")
3.6.4 Configurations for production use
Gzip
The frontend files and JSON responses from the server can sometimes be quite large and you should turn on gzip
to reduce the size for network traffic.
nginx
In /etc/nginx/nginx.conf
turn on gzip support by adding:
gzip on;
httpd
For httpd you can add these lines to your virtualhost configuration file:
# Enable gzip for these types
SetOutputFilter DEFLATE
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/plain
3.6.5 Example configurations
You can find some example configurations in https://github.com/oskariorg/sample-configs/tree/master/nginx. The nginx version at the time of writing the configs was 1.8.1 which was used to test these configurations.
Most configurations for nginx can be done in /etc/nginx/conf.d/default.conf
Apache httpd has a nice page for setting up reverse proxy: https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html
Assumptions
Below are some of the assumptions for the nginx example configurations.
Oskari frontend code.
Oskari frontend code should be made available in the server directory /opt/public/oskari
.
This can be changed by modifying these lines:
root /opt/public/;
# Oskari frontend files
location ^~ /Oskari/ {
rewrite ^/Oskari/(.*)$ $1 break;
try_files /oskari/$1 oskari/$1/ =404;
}
Oskari-server
Oskari server should be running on localhost in port 8080. This can be changed by modifying these lines:
upstream oskariserver {
server localhost:8080;
}
Protecting cookies
Before Oskari 3.0 the Java libraries didn't support the SameSite-flag for cookies but Set-Cookie
headers from the application server can be manipulated by both nginx and httpd.
We recommend using secure
, HttpOnly
and SameSite=Lax
flags for cookies.
This snippet modifies the cookie the application server gives and adds the flags whenever the application server wants to add a cookie. SameSite-flag means that browsers don't send for example the session cookie when requests originate from a different domain.
# Oskari-server application server path
location / {
...
# set all cookies to secure, httponly and samesite by modifying "path"
proxy_cookie_path / "/; secure; HttpOnly; SameSite=lax";
}
HTTPS-configuration
The following enables HTTPS on the server. Add the certificates on:
/etc/nginx/ssl/public.crt
for public key/etc/nginx/ssl/private.rsa
for private key
or change the configuration accordingly.
# ssl config - optional, but recommended for offering https-urls
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/public.crt;
ssl_certificate_key /etc/nginx/ssl/private.rsa;
# ssl security settings - optional, but recommended
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
server_tokens off;
# /ssl config
Check the chosen server software instructions for securing web servers/listing of current recommended protocols, ciphers etc. All the usual best practices work and hardening flags works with Oskari as any other web application. The only thing that makes things a bit different is if you allow users to published embedded maps from your application, these are embedded using iframe. Usual hardening tips might advice for disabling support for the service to be shown in an iframe, but embedded maps need this to be useful so you shouldn't disable embedding.
3.6.6 Server clustering (Optional)
Oskari server can be used in a clustered environment setup. A server cluster can be used to increase availability, reliability and scalability and help deal with software crashes/hardware failures etc in the system.
A simple clustered environment can be set up by having 1-n application servers (Tomcat/Jetty etc) running Oskari-server based webapp and having a load balancer like nginx or Apache httpd as a an entrypoint that forwards (and even load-balances) requests to the application servers. The requests can be forwarded in a round-robin fashion. "Sticky sessions" are not required but could benefit debugging etc (see Identified challenges).
Currently this means:
- User sessions can be saved/tracked in Redis (shared between nodes)
- Caches communicate removals/flushes between cluster nodes
- Programmatically setting log level is communicated between cluster nodes
Note! A "cluster" with just one server instance still means persistent sessions (sessions don't "die" with server restart etc) so it's worth considering.
Enabling cluster handling
Clustered environment handling is enabled with the oskari.profiles
key in oskari-ext.properties
:
# Comma-separated list of profiles to activate.
oskari.profiles=redis-session
Add redis-session
to the profiles list
Code examples for adding more cluster aware functionality
Check status
Check if we have cluster handling enabled:
boolean isClustered = org.oskari.cluster.ClusterManager.isClustered();
Messaging
Calling ClusterManager.getClientFor([functionality id])
returns a ClusterClient
instance that is created on first call and shared between returning calls. This keeps the number of Redis-connections manageable. The ClusterClient
can be used to send messages and listen to messages between cluster nodes (application server instances). The ClusterManager
handles that messages from an instance is not received by listeners of that same instance. ClusterClient
handles message scoping so messages from one functionality are not received by other functionalities. For example "cache" functionality doesn't receive messages from "logger" functionality making it easier to handle messages based on the functionality.
For example cache
is used by Oskari cache classes as functionality id.
Messaging also has a channel
concept that can be used to further filter messages for specific listeners. Channel could be considered an event name for usual event based code. In the cache functionality channel
is used to identify the cache instance (maplayer, dataprovider etc).
Sending messages
String functionalityId = "cache";
String channel = "maplayer";
String msg = "REM:1";
ClusterManager
.getClientFor(functionalityId)
.sendMessage(channel, msg);
This would send a message REM:1
to cache
functionality with channel maplayer
. This would signal other cluster nodes that cache
with name maplayer
should be notified with the message REM:1
. The functionality that is doing messaging is responsible for implementing the message parsing/protocol ie. what kind of message signifies what in the functionality.
Listening to messages
Listen to messages from other cluster nodes based on functionality id
and more specific message type channel
. The code below can be used to listen to messages from other cluster nodes that have been sent with the code snippet above.
String functionalityId = "cache";
String channel = "maplayer";
ClusterManager
.getClientFor(functionalityId)
.addListener(channel, (msg) -> handleClusterMsg(msg));
The handleClusterMsg()
will receive the REM:1
message from the above example and in the case of caches will remove/flush the value with key 1 (maplayer id used as cache key) from the cache so an updated version is loaded from the database when it's next requested.. Note that channel is used to identify the cache so only the maplayer
cache would remove the item with key 1, not for example a cache for dataproviders.
Identified challenges
Server clusters usually present some challenges for servers environments as well. Here's something we've identified:
Logging
Logging in clustered environment means that a single page view by a single user can generate log messages on different servers (different log files). This requires an instance specific solution like:
- "sticky session" where the load balancer in front of Oskari-server forwards requests from single user to the same server instance.
- a centralized logging system where the log from each node is gathered on a central system.
The centralized logging would also benefit from a "request id" that could be used to group log messages/user without identifying the user details. This hasn't been implemented as it is not trivial and would require passing some identifier to different parts of the system that don't require it now.