Exercise: Run Liferay and OpenSearch Using Docker
Subscription Required Liferay DXP 2026.Q1+
Walk through a minimal Liferay-OpenSearch setup on your local machine to see how a secure HTTPS connection between OpenSearch and Liferay is configured. The example uses two Docker containers — one for OpenSearch and one for Liferay — on a shared Docker network, with custom certificates that include the OpenSearch container’s hostname as a subject alternative name (SAN). For a complete installation guide, see Installing OpenSearch.
Before you begin, install Docker and OpenSSL.
Create Local Folders and Docker Network
-
Create the folder structure for bind mounting configuration and data into the containers. Since OpenSearch must write to the data folder, set its permissions accordingly:
mkdir -p test-opensearch-install/certs && \ mkdir -p test-opensearch-install/opensearch-data -m a+w && \ mkdir -p test-opensearch-install/dxp/files/osgi/configs && \ mkdir -p test-opensearch-install/dxp/deploy && \ cd test-opensearch-installTipThe
cd test-opensearch-installcommand puts you in thetest-opensearch-installfolder. Run all remaining commands from this folder. -
Create a Docker network so the containers can communicate by hostname:
docker network create opensearch-net
Generate Security Certificates
OpenSearch requires certificates for the transport layer (internal node communication) and the HTTP layer (client connections). The certificates must include DNS:opensearch as a SAN so Liferay’s SSL verification succeeds when connecting to the OpenSearch container by name on the Docker network. The steps below create a certificate authority (CA), sign a node certificate with it, and produce two files: a PKCS#12 keystore for OpenSearch and a separate truststore containing the CA certificate for Liferay to verify the connection.
-
Generate a certificate authority (CA):
openssl genrsa -out certs/ca.key 2048 openssl req -x509 -new -nodes -key certs/ca.key -sha256 -days 730 \ -out certs/ca.pem -subj "/CN=OpenSearch-CA" -
Generate a node key and certificate signing request:
openssl genrsa -out certs/opensearch.key 2048 openssl req -new -key certs/opensearch.key \ -out certs/opensearch.csr -subj "/CN=opensearch" -
Create a SAN extension file. The
DNS:opensearchentry matches the container name on the Docker network:printf 'subjectAltName=DNS:opensearch,DNS:localhost,IP:127.0.0.1' \ > certs/opensearch.ext -
Sign the certificate with the CA:
openssl x509 -req -sha256 -days 730 \ -in certs/opensearch.csr \ -CA certs/ca.pem -CAkey certs/ca.key -CAcreateserial \ -out certs/opensearch.pem \ -extfile certs/opensearch.ext -
Export to a PKCS#12 keystore:
openssl pkcs12 -export \ -in certs/opensearch.pem -inkey certs/opensearch.key \ -CAfile certs/ca.pem -chain \ -out certs/opensearch.p12 -passout pass:liferay -
Create a separate truststore containing the CA certificate as a trusted entry:
keytool -import -trustcacerts -alias ca -file certs/ca.pem \ -keystore certs/truststore.p12 -storetype PKCS12 \ -storepass liferay -noprompt -
Make the certificate files readable by the containers:
chmod a+r certs/*
Configure OpenSearch
Create an opensearch.yml file that configures the security plugin to use the PKCS#12 certificates. Save this file to the test-opensearch-install folder:
cluster.name: LiferayOpenSearchCluster
node.name: opensearch
network.host: 0.0.0.0
discovery.type: single-node
indices.query.bool.max_clause_count: 4096
plugins.security.ssl.transport.enabled: true
plugins.security.ssl.transport.keystore_type: PKCS12
plugins.security.ssl.transport.keystore_filepath: certs/opensearch.p12
plugins.security.ssl.transport.keystore_password: liferay
plugins.security.ssl.transport.truststore_type: PKCS12
plugins.security.ssl.transport.truststore_filepath: certs/truststore.p12
plugins.security.ssl.transport.truststore_password: liferay
plugins.security.ssl.transport.enforce_hostname_verification: false
plugins.security.ssl.http.enabled: true
plugins.security.ssl.http.keystore_type: PKCS12
plugins.security.ssl.http.keystore_filepath: certs/opensearch.p12
plugins.security.ssl.http.keystore_password: liferay
plugins.security.ssl.http.truststore_type: PKCS12
plugins.security.ssl.http.truststore_filepath: certs/truststore.p12
plugins.security.ssl.http.truststore_password: liferay
plugins.security.allow_default_init_securityindex: true
plugins.security.nodes_dn:
- 'CN=opensearch'
plugins.security.authcz.admin_dn:
- 'CN=admin'
Make the file readable by the OpenSearch container:
chmod a+r opensearch.yml
Start OpenSearch
Start the OpenSearch container on the opensearch-net network with the custom certificates and configuration mounted. Setting DISABLE_INSTALL_DEMO_CONFIG=true prevents the demo configuration installer from overwriting the custom opensearch.yml:
docker run -it -m 2g \
--name opensearch \
--network opensearch-net \
-e "DISABLE_INSTALL_DEMO_CONFIG=true" \
-p 9200:9200 \
-v $(pwd)/certs:/usr/share/opensearch/config/certs \
-v $(pwd)/opensearch.yml:/usr/share/opensearch/config/opensearch.yml \
-v $(pwd)/opensearch-data:/usr/share/opensearch/data \
opensearchproject/opensearch:2
On SELinux-enabled systems (e.g., Fedora, RHEL), add :z to each volume mount so the container can access the bind-mounted files:
docker run -it -m 2g \
--name opensearch \
--network opensearch-net \
-e "DISABLE_INSTALL_DEMO_CONFIG=true" \
-p 9200:9200 \
-v $(pwd)/certs:/usr/share/opensearch/config/certs:z \
-v $(pwd)/opensearch.yml:/usr/share/opensearch/config/opensearch.yml:z \
-v $(pwd)/opensearch-data:/usr/share/opensearch/data:z \
opensearchproject/opensearch:2
The first startup takes longer than usual because OpenSearch initializes the security index with the default configuration. Wait until you see a log message like [o.o.n.Node] [opensearch] started before continuing.
Install Analysis Plugins
Liferay requires the following analysis plugins in OpenSearch:
-
Open a new terminal window and exec into the running container:
docker exec -it opensearch /bin/bash -
Install the required plugins:
./bin/opensearch-plugin install analysis-icu analysis-kuromoji analysis-smartcn analysis-stempel -
Exit the shell:
exit -
Stop the OpenSearch container with CTRL+C, then restart it to register the plugins:
docker start -i opensearch
Configure Liferay
-
Create the configuration file to disable Elasticsearch-specific modules:
touch dxp/files/osgi/configs/com.liferay.portal.bundle.blacklist.internal.configuration.BundleBlacklistConfiguration.configOpen the file and give it these contents:
blacklistBundleSymbolicNames=[\ "com.liferay.portal.search.elasticsearch.cross.cluster.replication.impl",\ "com.liferay.portal.search.elasticsearch.monitoring.web",\ "com.liferay.portal.search.elasticsearch8.api",\ "com.liferay.portal.search.elasticsearch8.impl",\ "com.liferay.portal.search.learning.to.rank.api",\ "com.liferay.portal.search.learning.to.rank.impl"\ ]NoteIn Liferay DXP 2025.Q1–Q4, the Elasticsearch bundle symbolic names contain
elasticsearch7instead ofelasticsearch8. -
Create the OpenSearch configuration file:
touch dxp/files/osgi/configs/com.liferay.portal.search.opensearch2.configuration.OpenSearchConfiguration.configOpen the file and give it these contents:
remoteClusterConnectionId="REMOTE" -
Create the connection configuration file:
touch dxp/files/osgi/configs/com.liferay.portal.search.opensearch2.configuration.OpenSearchConnectionConfiguration-REMOTE.configOpen the file and give it these contents:
active=B"true" authenticationEnabled=B"true" connectionId="REMOTE" httpSSLEnabled=B"true" networkHostAddresses=["https://opensearch:9200"] password="admin" truststorePassword="liferay" truststorePath="/opt/liferay/opensearch/certs/truststore.p12" truststoreType="pkcs12" username="admin"WarningThis uses the default demo admin credentials (
admin/admin) from OpenSearch’s security plugin. This is acceptable for a local exercise but must not be used in production. See OpenSearch’s security documentation for configuring authentication properly.
Deploy the OpenSearch Connector
Download the Liferay Connector to OpenSearch 2 from Liferay Marketplace following the steps in Installing OpenSearch. Once you have the LPKG file, copy it to the dxp/deploy/ folder:
cp /path/to/liferay-connector-to-opensearch-2.lpkg dxp/deploy/
Liferay picks up the connector from this folder automatically on startup.
Start Liferay
Start the Liferay container on the same opensearch-net network. Mount the DXP configuration folder and the certificates folder:
docker run -it --memory 9g \
--name liferay \
--network opensearch-net \
--publish 8080:8080 \
--volume $(pwd)/dxp:/mnt/liferay \
--volume $(pwd)/certs:/opt/liferay/opensearch/certs \
liferay/portal:7.4.3.132-ga132
On SELinux-enabled systems (e.g., Fedora, RHEL), add :z to each volume mount:
docker run -it --memory 9g \
--name liferay \
--network opensearch-net \
--publish 8080:8080 \
--volume $(pwd)/dxp:/mnt/liferay:z \
--volume $(pwd)/certs:/opt/liferay/opensearch/certs:z \
liferay/portal:7.4.3.132-ga132
Checkpoint: Once Liferay starts, verify the OpenSearch connection is active in Control Panel → Configuration → Search.

Reindex the search and spell check indexes from the Index Actions tab in Control Panel → Configuration → Search.
Clean Up
To remove everything created for this exercise, first stop both containers, then:
-
Remove the containers:
docker container rm opensearch liferay -
Remove the Docker network:
docker network rm opensearch-net -
Remove the folder structure. First make sure you’re in the parent of the
test-opensearch-installfolder, then run:rm -fr test-opensearch-install