# Configuration Changes to Make after Installing ORDS Standalone

# Introduction

These days, I nearly always deploy ORDS in Standalone mode. Standalone mode allows you to run ORDS without deploying it within a container like Tomcat or Weblogic, thus simplifying your technology stack. Oracle fully supports ORDS running in standalone mode. This is possible because ORDS comes bundled with its own HTTP server, [Jetty](https://projects.eclipse.org/projects/rt.jetty).

Given that you are no longer deploying ORDS in a container, there are a few things you need to do to make sure you obtain comparable results. In this post, I will review the steps I typically take when configuring a new ORDS Server running in Standalone mode.

<div data-node-type="callout">
<div data-node-type="callout-emoji">🔢</div>
<div data-node-type="callout-text">This post was created based on ORDS version 23.2.3.r2421937</div>
</div>

# Prerequisites

## Set Environment Variables

When I work with ORDS on the command line, I typically set the following environment variables for my user profile. These cut down on typing and provide a consistent way to access the ORDS binary and config files.

```bash
# Set a varibale to the Home Directory for ORDS. 
# You should see files like license.txt and index.html in this folder.
# This is also where the bin folder is located.
export ORDS_HOME=/opt/oracle/ords/
# Set a variable pointing to your ORDS Config files.
export ORDS_CONFIG=/etc/ords/config
# Add the ORDS binary to your Path.
export PATH=${ORDS_HOME}/bin:${PATH}
```

# Enable Access Logs

Access logs are an essential part of securing your system and can also be helpful when troubleshooting issues.

You can enable access logs by running the following command:

```bash
ords --config $ORDS_CONFIG config set standalone.access.log /var/log/ords

ORDS: Release 23.2 Production on Mon Oct 02 22:28:36 2023
Copyright (c) 2010, 2023, Oracle.
Configuration:
  /var/log/ords
The global setting named: standalone.access.log was set to: /var/log/ords
```

This command will add the following entry to the `$ORDS_CONFIG/global/settings.xml` File: `<entry key="standalone.access.log">/var/log/ords</entry>` . After you restart ORDS, access logs will created in the `/var/log/orda` directory.

The resulting access log files will be named `ords_YYYY_MM_DD.log` and will be rotated daily. The log format matches the [NCSA Common Log Format](https://en.wikipedia.org/wiki/Common_Log_Format).

```bash
10.0.0.79 - - [02/Oct/2023:17:35:47 +0000] "GET http://10.0.0.74:8080/ords/demo/test/ping HTTP/1.1" 200 94
10.0.0.79 - - [02/Oct/2023:17:39:12 +0000] "POST /ords/wwv_flow.ajax?p_context=app-builder/page-designer/9123695687705 HTTP/1.1" 200 475
10.0.0.79 - - [02/Oct/2023:17:39:12 +0000] "POST /ords/wwv_flow.ajax?p_context=app-builder/page-designer/9123695687705 HTTP/1.1" 200 42503
10.0.0.79 - - [02/Oct/2023:17:39:12 +0000] "POST /ords/wwv_flow.ajax?p_context=app-builder/page-designer/9123695687705 HTTP/1.1" 200 1517
10.0.0.79 - - [02/Oct/2023:17:39:14 +0000] "POST /ords/wwv_flow.ajax?p_context=app-builder/page-designer/9123695687705 HTTP/1.1" 200 102
10.0.0.79 - - [02/Oct/2023:17:39:50 +0000] "POST /ords/wwv_flow.ajax?p_context=app-builder/page-designer/9123695687705 HTTP/1.1" 200 780
10.0.0.79 - - [02/Oct/2023:17:40:46 +0000] "GET http://10.0.0.74:8080/ords/demo/test/ping HTTP/1.1" 200 94
```

<div data-node-type="callout">
<div data-node-type="callout-emoji">🗄</div>
<div data-node-type="callout-text">Don't forget to write a shell script to zip and archive these log files occasionally, as they can get quite large.</div>
</div>

# Enable Response Compression

As I mentioned in my post, [Building Performant REST Services with Oracle REST Data Services](https://blog.cloudnueva.com/ords-performant-rest-services) compressing response content can bring significant performance benefits. You can enable response compression by creating a file called `jetty-compression.xml` in the folder `$ORDS_CONFIG/global/standalone/etc`.

Example Content for the file `jetty-compression.xml`

```xml
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
      <Call name="insertHandler">
        <Arg>
          <New id="GZipHanlder" class="org.eclipse.jetty.server.handler.gzip.GzipHandler">
            <Set name="IncludedMimeTypes">
              <Array type="java.lang.String">
                <Item>text/html</Item>
                <Item>text/xml</Item>
                <Item>text/css</Item>
                <Item>text/javascript</Item>
                <Item>application/javascript</Item>
                <Item>application/json</Item>
              </Array>
            </Set>
            <Set name="minGzipSize">128</Set>
          </New>
        </Arg>
      </Call>
</Configure>
```

* `IncludedMimeTypes` is used to control what types of files should be zipped.
    
* `minGzipSize` is used to control how many bytes the response must be before it is zipped.
    

# Assign JVM Memory

I advise that you explicitly set the size of the JVM ORDS runs to take advantage of the available memory on the ORDS Server. For example, if an ORDS server has 4 GB of RAM, I typically assign 2 GB to the ORDS JVM.

You can set the JVM size by populating the environment variable `_JAVA_OPTIONS` in your ORDS startup script. The following example sets the JVM to 2 GB.

```bash
export _JAVA_OPTIONS="-Xms2048M -Xmx2048M"
```

# ORDS Startup & Shutdown Scripts

You will need to create a startup and a shutdown script so you can set specific values before you start ORDS and so that you can run ORDS in the background.

I use an exact copy of Tim Hall's startup and shutdown scripts in [this post](https://oracle-base.com/articles/misc/oracle-rest-data-services-ords-standalone-mode-22-onward#start-stop). I am including them here for completeness. I have also changed the paths in these scripts to match those used in the rest of my post.

After creating the below scripts, you should make them executable as follows:

```bash
chmod u+x ~/scripts/*.sh
```

## Startup Script

Create a file called ~/scripts/start\_ords.sh with the following content (change paths as necessary):

```bash
#!/bin/bash
export PATH=/usr/sbin:/usr/local/bin:/usr/bin:/usr/local/sbin:$PATH
export JAVA_HOME=/u01/java/latest
export ORDS_HOME=/opt/oracle/ords/
export ORDS_CONFIG=/etc/ords/config
LOGFILE=/etc/ords/logs/ords-`date +"%Y""%m""%d"`.log
export _JAVA_OPTIONS="-Xms2048M -Xmx2048M"
nohup ${ORDS_HOME}/bin/ords --config ${ORDS_CONFIG} serve >> $LOGFILE 2>&1 &
echo "View log file with : tail -f $LOGFILE"
```

You can then start ORDS using the following command:

```bash
~/scripts/start_ords.sh
```

## Shutdown Script

```bash
#!/bin/bash
export PATH=/usr/sbin:/usr/local/bin:/usr/bin:/usr/local/sbin:$PATH
kill `ps -ef | grep [o]rds.war | awk '{print $2}'`
```

You can then stop ORDS using the following command:

```bash
~/scripts/stop_ords.sh
```

# Run ORDS as a Service

As an alternative to creating startup and shutdown scripts for ORDS, I often create a Linux Service to control ORDS startup and shutdown. The steps below were inspired by the blog post [Run ORDS as a systemd Service](https://ruepprich.com/run-ords-as-a-systemd-service/) by [Christopher Ruepprich](https://www.linkedin.com/in/cruepprich/) with changes to accommodate later versions of ORDS.

## Steps

```bash
sudo vi /etc/systemd/system/ords.service
```

```bash
[Unit]
Description=ORDS Service

[Service]
SyslogIdentifier=ords
User=root
Restart=always
RestartSec=30
TimeoutStartSec=30
TimeoutStopSec=30
EnvironmentFile=/etc/ords/scripts/ords_exports.sh
ExecStart=/usr/bin/bash -c '${ORDS_HOME}/bin/ords --config ${ORDS_CONFIG} serve'
ExecStop=kill `ps -ef | grep [o]rds.war | awk '{print $2}'`

[Install]
WantedBy=multi-user.target
```

The file /etc/ords/scripts/ords\_exports.sh looks like this:

```bash
PATH=/usr/sbin:/usr/local/bin:/usr/bin:/usr/local/sbin:$PATH
JAVA_HOME=/u01/java/latest
ORDS_HOME=/opt/oracle/ords
ORDS_CONFIG=/etc/ords/config
_JAVA_OPTIONS="-Xms1536M -Xmx1536M"
```

You can then start/stop ORDS with these commands:

```bash
sudo systemctl start ords
sudo systemctl stop ords
sudo systemctl restart ords
```

Finally, you can view the ORDS Log files as follows:

```bash
journalctl -f -u ords.service
```

# Running ORDS Behind a Load Balancer

Usually, when I deploy ORDS, I deploy it behind a Load Balancer. The Load Balancer handles receiving HTTPS requests over SSL/TLS and routes requests to one or more ORDS servers (preferably more) running over HTTP. In this scenario, SSL Termination is happening in ORDS.

<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Of course, you can also add the same certificate to the ORDS server that you add to your Load Balancer and have HTTPS on your ORDS Server and the Load Balancer. See <a target="_blank" rel="noopener noreferrer nofollow" href="https://blogs.oracle.com/fusionmiddlewaresupport/post/simplified-ssl-configuration-for-ords-a-howto-guide" style="pointer-events: none">this post</a> for more details on adding an SSL Certificate to your ORDS Server.</div>
</div>

If you do terminate SSL at the Load Balancer, then there are two alternate configurations that you need to make. Configuration 1 works fine with an OCI Load Balancer but not other Load Balancers (e.g., HA Proxy). If Configuration 1 does not work for you, then try Configuration 2.

## Configuration 1

```bash
# Allow access from example.com
ords --config $ORDS_CONFIG config set security.externalSessionTrustedOrigins https://example.com
# Verify HTTP Header Contains X-Forwarded-Proto: https
ords --config $ORDS_CONFIG config set security.httpsHeaderCheck "X-Forwarded-Proto: https"
```

```xml
<entry key="security.externalSessionTrustedOrigins">https://example.com</entry>
<entry key="security.httpsHeaderCheck">X-Forwarded-Proto: https</entry>
```

## Configuration 2

```bash
# Allow access from example.com
ords --config $ORDS_CONFIG config set security.externalSessionTrustedOrigins https://example.com
# Force HTTPS
ords --config $ORDS_CONFIG config set security.forceHTTPS true
```

This will result in two new settings being added to `$ORDS_CONFIG/global/settings.xml`.

```xml
<entry key="security.externalSessionTrustedOrigins">https://example.com</entry>
<entry key="security.forceHTTPS">true</entry>
```

# Other Items

While not specific to running ORDS in Standalone mode, you should consider the following when firing up a new ORDS server.

## Size the ORDS Connection Pool

ORDS uses a database connection pool to connect to the Oracle Database. You must size this correctly when configuring a new ORDS instance. I won't go into how to size the database pool in this post, but you should set the below settings based on your determination of the pool size:

* jdbc.InitialLimit - Determines how many DB connections ORDS creates when you first start ORDS.
    
* jdbc.MinLimit - Determines how many DB connections ORDS should keep open even when no activity exists.
    
* jdbc.MaxLimit - Determines the maximum number of DB connections ORDS is allowed to create.
    

![ORDS Connection Diagram](https://cdn.hashnode.com/res/hashnode/image/upload/v1696291558752/b8075c15-44c2-4fde-8976-f231ca79ad3a.png align="center")

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">The challenge is balancing how many connections you want ORDS to use during the quiet times versus how long it takes for ORDS to start new connections when demand increases.</div>
</div>

The following ORDS config commands set these values in the `$ORDS_CONFIG/global/settings.xml` file.

```bash
ords --config $ORDS_CONFIG config set jdbc.InitialLimit 15
ords --config $ORDS_CONFIG config set jdbc.MinLimit 15
ords --config $ORDS_CONFIG config set jdbc.MaxLimit 25
```

Entries in `$ORDS_CONFIG/global/settings.xml`

```xml
<entry key="jdbc.InitialLimit">15</entry>
<entry key="jdbc.MaxLimit">25</entry>
<entry key="jdbc.MinLimit">15</entry>
```

### Initial = Min = Max

Thanks to @[Connor McDonald](@connormcdonald) for his comment on this post. In his comment, he refers to this very detailed [presentation](https://www.neooug.org/gloc/Presentations/2019/Koopelears_ConnectionPoolSizingConcepts.pdf) from Toon Koppelaars on connection pools and introduces an interesting approach to connection pool sizing. His comment in full (with some edits from Grammarly) is this:

> The TL;DR rationale from the presentation for that recommendation is:
> 
> * unused pool sessions are idle; they do nothing and consume minimal resources because the last thing pool-based apps do is free their resources when they give back a connection. If they don't, you have an app bug, not a connection pool config issue.
>     
> * the max size setting (by definition) is what you are prepared to let your server handle without undue stress, so why would you pick a minimum/initial less than that? To do so means your apps incur the cost of creating a connection pseudo-randomly. That makes response times variable.
>     

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">I thought Connor's point was well worth adding to the post. Maybe because my dad was an Accountant, the thought of the wasted CPU prevented me from thinking of this before 😊</div>
</div>

## Enable Metadata Caching

When a client calls an ORDS REST Service, ORDS must first fetch the REST service definition from the ORDS Metadata and then execute the code contained in the REST service definition.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1696292677059/b73615ab-73e9-4a26-9250-d88ee998bdf9.png align="center")

With Metadata Caching turned on, ORDS can get the REST Service definition from a cached version on the ORDS server, eliminating a round trip to the database.

![ORDS Metadata Caching](https://cdn.hashnode.com/res/hashnode/image/upload/v1696292634221/0a4c3eb8-67b2-4f43-ad3e-4a38ed67096f.png align="center")

You can enable Metadata Caching by adding the following properties to the `$CONFIG_HOME/global/settings.xml` file.

```bash
ords --config $ORDS_CONFIG config set cache.metadata.enabled true
ords --config $ORDS_CONFIG config set cache.metadata.timeout 1m
```

| **Property** | **Description** |
| --- | --- |
| cache.metadata.enabled | Enable or disable metadata caching. |
| cache.metadata.timeout | Specify how long the metadata remains in the cache before the cache is refreshed from ORDS Metadata in the database. |

# Conclusion

Running ORDS in Standalone mode is fully supported by Oracle and allows you to remove Tomcat or Weblogic Containers from your ORDS stack. Following the suggestions in this post will enable you to achieve this while maintaining the features and performance these containers provided in the past.

## Special Thanks

* Thanks to @[Richard Soule](@RichSoule) for his comment regarding placing the log files on a separate disk partition. This way, if the logs fill the partition, ORDS will keep running.
    
* Thanks to @[Jeff Smith](@thatjeffsmith) for his comment on LinkedIn: "As for default memory allocation for the JVM, it depends on version of Java but basically comes down to the % of the physical memory on the device/machine."
    
* Thanks to the suggestion from Alain LACOUR on LinkedIn: "Beyond creating start and stop scripts I would even recommend to run ORDS standalone as a service so it can start by itself and stop properly when the server is restarted for any reason."
    

## 🔗 Read More

* 📝 [ORDS Posts](https://blog.cloudnueva.com/tag/ords)
