Skip to main content

Creating OSGi Modules and Sharing Packages

  Overview This guide walks through creating two OSGi modules in Liferay 7.4 and sharing a Java package between them using the standard API + Implementation pattern. This is the most common and correct approach for exposing reusable services in a Liferay-based architecture. In OSGi, a bundle (module) does not expose its internal packages by default — everything is private unless explicitly exported. To share code between modules, the standard practice is to split functionality into: · An API module — contains interfaces/DTOs and exports the package · A Service (Implementation) module — implements the interface, imports the package, and registers the implementation as an OSGi component/service The consuming module then simply imports the API package and looks up the service using @Reference injection. Step 1: Create the API Module Using Liferay Workspace + Blade CLI, generate a new API module: blade create -t api -p com.sgc.greeting greeting-api This generates a Gradle module unde...

Liferay DXP 7.4 Cluster with Load Balancing

Liferay DXP Cluster with Load Balancing


1. Overview

This document provides a detailed explanation of every directive and block in the NGINX configuration file used to set up a reverse proxy and load balancer for a two-node Liferay DXP cluster running on a single machine (localhost). Each section is dissected line-by-line so that trainees and administrators gain a complete understanding of the role each directive plays.

2. Architecture Overview

The configuration implements the following layered architecture


Layer

Component

Port

Role

Client / Browser

End User

80

Sends HTTP requests

Reverse Proxy

NGINX

80

Receives, routes, and forwards requests

Backend Node 1

Liferay DXP Instance 1

8080

Serves application content

Backend Node 2

Liferay DXP Instance 2

9090

Serves application content

Key Principle: NGINX acts as the single entry point. All user traffic arrives at port 80 and is intelligently distributed across the two Liferay backend nodes. Users are unaware of the internal cluster topology.

3. Complete Configuration File

The full nginx.conf used in this setup is as follows:



worker_processes 1;


events {
worker_connections 1024;
}


http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;


# 1. Define your two local Liferay backend nodes
upstream liferay_cluster {
ip_hash;
server 127.0.0.1:8080; # Liferay Node 1
server 127.0.0.1:9090; # Liferay Node 2
}


# 2. NGINX Front-end Server (Listens on port 80)
server {
listen 80;
server_name localhost;


location / {
proxy_pass http://liferay_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}


error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

4. Global Block

4.1 worker_processes

worker_processes 1;

What it does: Defines how many NGINX worker processes will be started.

  • Each worker process handles connections independently using non-blocking I/O.
  • Value 1 means only one worker process is spawned — suitable for a single-CPU development or training environment.
  • In production, this is typically set to auto to match the number of available CPU cores.



Value

Use Case

Notes

1

Development / Training

Simple, easy to debug

auto

Production

Matches CPU core count automatically

4

4-core server

Manual override for specific tuning

5. Events Block

events {
worker_connections 1024;
}

5.1 worker_connections

What it does: Sets the maximum number of simultaneous connections a single worker process can handle.

  • Value 1024 means each worker can handle up to 1024 concurrent connections.
  • Total maximum connections = worker_processes x worker_connections = 1 x 1024 = 1024 connections.
  • In production with auto workers on an 8-core machine: 8 x 1024 = 8192 total connections.
  • This includes all connections: client-to-NGINX and NGINX-to-backend.

6. HTTP Block

The http block is the core of NGINX web server configuration. It contains all directives related to HTTP processing, upstream definitions, and virtual server configurations.

6.1 include mime.types

include mime.types;

What it does: Loads the MIME type mappings from the external file mime.types.

  • MIME types tell the browser what kind of file is being sent (e.g., text/html for HTML, image/png for PNG files).
  • Without this, the browser may not correctly render CSS, JavaScript, images, etc.
  • The mime.types file is located in the NGINX conf/ directory.

6.2 default_type

default_type application/octet-stream;

What it does: Sets the fallback MIME type for any file whose type is not mapped in mime.types.

  • application/octet-stream is the generic binary stream type.
  • When a browser receives this, it will typically prompt the user to download the file.

6.3 sendfile

sendfile on;

What it does: Enables the use of the OS-level sendfile() system call for transferring files.

  • Without sendfile: File data is copied to user-space memory, then written to the socket (2 copies).
  • With sendfile on: Data is transferred directly from file descriptor to socket in kernel-space (0 user-space copies).
  • This dramatically improves performance when serving static files.
  • For a proxy scenario (like ours), its impact is limited since we are not serving files directly.

6.4 keepalive_timeout

keepalive_timeout 65;

What it does: Sets how long (in seconds) NGINX will keep an idle client connection open (HTTP keep-alive).

  • Value 65 seconds: After the last response, NGINX waits 65 seconds before closing the connection.
  • Why keep connections alive? Opening a new TCP connection has overhead (3-way handshake). Keep-alive allows reuse.
  • This is especially important for Liferay portals because a single page load triggers many HTTP requests (JS, CSS, images).

7. Upstream Block — Defining the Cluster

upstream liferay_cluster {
ip_hash;
server 127.0.0.1:8080; # Liferay Node 1
server 127.0.0.1:9090; # Liferay Node 2
}

The upstream block defines a named group of backend servers. NGINX refers to this group by name when proxying requests.

7.1 upstream liferay_cluster

Name: liferay_cluster — This is a logical name assigned to the group of backend servers. It is referenced in the proxy_pass directive.

7.2 ip_hash — Sticky Sessions

ip_hash;

What it does: Enables session persistence (sticky sessions) based on the client's IP address.

  • NGINX computes a hash of the client's source IP address.
  • All requests from that IP are always routed to the same backend server.
  • This is critical for Liferay because Liferay stores session state (logged-in user, portlet state) in memory on the node.

Why ip_hash is needed for Liferay


Without ip_hash

With ip_hash

User logs in to Node 1

User logs in to Node 1

Next request goes to Node 2

Next request also goes to Node 1

Node 2 has no session — user is logged out!

Session is intact — user stays logged in

Broken user experience

Seamless user experience

Alternative: If Liferay cluster is properly configured with a shared session store (e.g., Infinispan/Ehcache), then ip_hash may not be required. However, for single-machine demo/training environments, ip_hash is the simplest and most reliable approach.

7.3 Backend Server Definitions

server 127.0.0.1:8080; # Liferay Node 1
server 127.0.0.1:9090; # Liferay Node 2

Each server directive registers a backend node in the upstream group


Directive

IP Address

Port

Description

server 127.0.0.1:8080

127.0.0.1 (localhost)

8080

Liferay DXP Node 1 — first Tomcat instance

server 127.0.0.1:9090

127.0.0.1 (localhost)

9090

Liferay DXP Node 2 — second Tomcat instance

  • Both instances run on the same machine (127.0.0.1) but listen on different ports.
  • In production, these would be different IP addresses on separate physical or virtual machines.
  • Since ip_hash is active, load balancing algorithm assigns each client IP deterministically to one of these nodes.

8. Server Block — Virtual Server

server {
listen 80;
server_name localhost;
...

8.1 listen 80

What it does: Instructs NGINX to listen for incoming HTTP connections on TCP port 80.

  • Port 80 is the default HTTP port. Browsers connect here when no explicit port is specified in the URL.
  • To enable HTTPS (TLS), you would add a second server block listening on port 443 with SSL certificates.

8.2 server_name localhost

What it does: Defines which domain name(s) this server block responds to.

  • Value localhost: This virtual server only responds when the HTTP request's Host header is localhost.
  • In production, this would be set to your domain name, e.g., server_name portal.company.com;
  • Multiple names are supported: server_name example.com www.example.com;

9. Location Block — Proxy Configuration

location / {
proxy_pass http://liferay_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}

9.1 location /

What it does: Matches all incoming request paths and applies the nested directives.

  • The / pattern is the most general location prefix — it matches everything.
  • NGINX uses the most specific matching location block. Since / is the only one here, all traffic is handled here.

9.2 proxy_pass

proxy_pass http://liferay_cluster;

What it does: Forwards the incoming client request to the upstream group named liferay_cluster.

  • NGINX applies the ip_hash algorithm and selects either 127.0.0.1:8080 or 127.0.0.1:9090.
  • NGINX acts as an intermediary: receives from client, forwards to backend, receives backend response, sends to client.
  • The client never knows which backend node served the request.

9.3 Proxy Headers (Deep Explanation)

These headers pass important client metadata from NGINX to Liferay. Without them, Liferay would see all requests as coming from NGINX (127.0.0.1) rather than the actual client.

9.3.1 proxy_set_header Host $host

proxy_set_header Host $host;

$host: NGINX variable containing the value of the Host header from the original client request.

Without this, Liferay receives the upstream group name (liferay_cluster) as the Host, which causes URL generation errors. Liferay uses the Host header to generate absolute URLs in portal pages.

9.3.2 proxy_set_header X-Real-IP $remote_addr

proxy_set_header X-Real-IP $remote_addr;

$remote_addr: The actual IP address of the connecting client.

Passes the original client IP address to Liferay via the X-Real-IP custom header. Liferay uses this for audit logging, access control, geolocation, and rate limiting.

9.3.3 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

$proxy_add_x_forwarded_for: Appends the client's IP to any existing X-Forwarded-For header.

This is the standard header for passing the full chain of proxy IP addresses. If there are multiple proxies in the chain: X-Forwarded-For: client-ip, proxy1-ip, proxy2-ip. Liferay reads this to identify the true originating client.

9.3.4 proxy_set_header X-Forwarded-Proto $scheme

proxy_set_header X-Forwarded-Proto $scheme;

$scheme: The protocol used by the client — either http or https.

This is critical for SSL termination. If NGINX handles HTTPS and forwards as HTTP internally: $scheme = https. Liferay reads X-Forwarded-Proto to decide whether to generate https:// or http:// URLs and to enforce security policies.

9.4 proxy_redirect off

proxy_redirect off;

What it does: Disables automatic rewriting of Location and Refresh headers in the backend's HTTP redirects.

  • When a backend server sends a redirect (e.g., HTTP 302 to http://127.0.0.1:8080/web/guest), NGINX would normally try to rewrite the URL.
  • With proxy_redirect off, NGINX passes the Location header unchanged.
  • Since our proxy_set_header Host directive already passes the correct host to Liferay, Liferay generates correct redirect URLs automatically.
  • This prevents double-rewriting which could corrupt redirect URLs.

10. Error Page Configuration

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}

10.1 error_page directive

What it does: Maps specific HTTP error status codes to a custom error page URI.

HTTP Status Code

Meaning

Common Cause

500

Internal Server Error

Unhandled exception in Liferay application

502

Bad Gateway

Backend (Liferay) is down or not responding

503

Service Unavailable

Backend overloaded or in maintenance

504

Gateway Timeout

Backend took too long to respond (timeout)

10.2 Custom Error Page Location

location = /50x.html {
root html;
}

  • location = /50x.html: Exact match — only handles the path /50x.html.
  • root html: Serves the file from the html/ directory within NGINX's installation directory.
  • NGINX ships with a default 50x.html file at nginx/html/50x.html.

11. Complete Directive Reference Table

Directive

Block

Value / Setting

Purpose

worker_processes

Global

1

Number of NGINX worker processes

worker_connections

events

1024

Max connections per worker

include

http

mime.types

Load MIME type definitions

default_type

http

application/octet-stream

Fallback MIME type

sendfile

http

on

Kernel-space file transfer optimization

keepalive_timeout

http

65

Idle connection lifetime (seconds)

upstream

http

liferay_cluster

Define backend server group

ip_hash

upstream

Sticky sessions by client IP

server (upstream)

upstream

127.0.0.1:8080/9090

Backend Liferay node addresses

listen

server

80

NGINX listens on HTTP port 80

server_name

server

localhost

Virtual host name

proxy_pass

location

http://liferay_cluster

Forward requests to upstream

proxy_set_header Host

location

$host

Pass original Host header

proxy_set_header X-Real-IP

location

$remote_addr

Pass client IP to backend

proxy_set_header X-Forwarded-For

location

$proxy_add_x_forwarded_for

Pass proxy chain IPs

proxy_set_header X-Forwarded-Proto

location

$scheme

Pass protocol (http/https)

proxy_redirect

location

off

Disable redirect URL rewriting

error_page

server

500 502 503 504

Custom error page mapping

2. Production Recommendations

While this configuration is ideal for training and demo purposes, the following enhancements are recommended for production deployments:

12.1 Enable HTTPS/TLS

  • Add a second server block listening on port 443 with ssl certificate paths.
  • Redirect HTTP to HTTPS using a return 301 https://$host$request_uri directive.

12.2 Increase Worker Processes

worker_processes auto;

  • Use auto to match the number of CPU cores available on the server.

12.3 Add Health Checks

upstream liferay_cluster {
ip_hash;
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server 127.0.0.1:9090 max_fails=3 fail_timeout=30s;
}

  • max_fails=3: After 3 failed connection attempts, mark server as unavailable.
  • fail_timeout=30s: Server is considered unavailable for 30 seconds.

12.4 Tune Timeouts

proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 300s;

proxy_read_timeout should be increased for Liferay portals because some requests (reports, document export) can take several minutes.

12.5 Buffer Configuration

proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;

Liferay responses can contain large cookies and headers. Increase buffer sizes to prevent buffering errors.

Comments

Popular posts from this blog

service builder with crud operation in liferay

   Crud and Search opration in Liferay:      ->  Liferay use service builder techniq for Crud opration.    ->  Service builder purform by  Service.xml file.    ->  Service.xml file create table in database and also create class and diffrent method.   1)      Create service.xml file.             ->Create service.xml file in WEB-INF and write below code.             ->CODE:        < service-builder package-path = "com.test" >         < namespace > qr </ namespace >           < entity name = "Searchclass" local-service = "true"                     ...

How to create new site programmaticly in liferay with validation

Create site in liferay <%@page import="javax.portlet.PortletPreferences"%> <%@page import="com.liferay.portal.kernel.util.ParamUtil"%> <%@page import="com.liferay.portal.kernel.util.HtmlUtil"%> <%@page import="com.liferay.portal.kernel.util.StringPool"%> <%@page import="com.liferay.portal.kernel.util.UnicodeProperties"%> <%@page import="com.liferay.portal.service.LayoutSetPrototypeServiceUtil"%> <%@page import="com.liferay.portal.model.LayoutSetPrototype"%> <%@page import="com.liferay.portal.service.GroupLocalServiceUtil"%> <%@page import="java.util.List"%> <%@page import="com.liferay.portal.kernel.bean.BeanParamUtil"%> <%@page import="com.liferay.portal.theme.ThemeDisplay"%> <%@page import="com.liferay.portal.model.Group"%> <%@page import="com.liferay.portal.kernel.util.WebK...

The Ultimate Guide to Liferay DXP Performance Tuning: Speed Up Your Portal

The Ultimate Guide to Liferay DXP Performance Tuning: Speed Up Your Portal In the enterprise web space, milliseconds equal millions. Whether you are running a B2B commerce storefront, a customer support portal, or an employee intranet on Liferay DXP, slow load times will devastate your user experience and destroy your SEO rankings. Out of the box, Liferay is configured to run on almost any machine. This means its default settings are highly conservative to ensure compatibility, not maximum performance. If you are launching a production environment without tuning your server, you are leaving massive amounts of speed and scalability on the table. In this comprehensive, deep-dive guide, we are going to explore the critical layers of Liferay performance tuning. We will cover backend Java Virtual Machine (JVM) configuration, Database Connection Pooling, Elasticsearch optimization, and Frontend caching strategies. By the end of this guide, you will have a blazing-fast, enterprise-grade...