Skip to content

Instantly share code, notes, and snippets.

@bagasme
Last active February 20, 2024 23:05
Show Gist options
  • Save bagasme/1de1908c86303c83b7bd51d50a12e041 to your computer and use it in GitHub Desktop.
Save bagasme/1de1908c86303c83b7bd51d50a12e041 to your computer and use it in GitHub Desktop.
Setting Up Guides for Apache OFBiz

Installing OFBiz

OFBiz (Open for Business) is a free and open source ERP solution by Apache, flexible enough to be used across any industries and business.

In this file of this gist, we will install OFBiz, with default setup. This use embedded Apache Derby as database backend, and loaded with default dataset included with the distribution.

Prerequisites

  • You need to have JDK 8 (not just JRE, but full JDK) installed on your system. Most Linux distributions should provided OpenJDK 8 package, but you can also install official JDK build from Oracle. Also, ensure that JDK binaries are on PATH and JDK installation directory is set on JAVA_HOME, as described in Adding JDK to Shell

Creating OFBiz User

Create user dedicated to running OFBiz instance, separated from other users. This way, if this account is compromised, it can be deleted along with OFBiz instance.

On Debian-based systems:

# addgroup ofbiz-operator
# adduser --ingroup ofbiz-operator ofbiz

On other systems:

# groupadd ofbiz-operator
# useradd -g ofbiz-operator ofbiz

In subsequent sections in this file, and on other files in this gist, all commands are run as ofbiz user. Switch user first:

# su ofbiz

Adding JDK to Shell

As in other Java applications, OFBiz requires that JAVA_HOME is set to JDK directory, and JDK binaries (such as java) are on PATH.

Append to ~/.bashrc and ~/.bash_profile:

export JAVA_HOME=/path/to/jdk8
export PATH=$PATH:$JAVA_HOME/bin

Downloading OFBiz

Use wget to download OFBiz, then extract it to /opt. Change directory if yours different. At the time of writing, the latest version is 16.11.05. If you come from the future, see Download Page and substitute links and files to latest version accordingly:

$ wget -c https://www-eu.apache.org/dist/ofbiz/apache-ofbiz-16.11.05.zip
# unzip apache-ofbiz-16.11.05.zip -d /opt

Rename directory to ofbiz, for easier reference:

# mv /opt/apache-ofbiz-16.11.05 /opt/ofbiz

Change ownership to ofbiz user:

# chown -R ofbiz:ofbiz-operator /opt/ofbiz

Building and Running OFBiz

cd to OFBiz directory:

$ cd /opt/ofbiz

OFBiz is distributed as source code, with gradle as its build system. In order to run OFBiz, it must be compiled first. As such, gradlew (gradle wrapper script) will be utilized for compilation. This script is also used to start and stop OFBiz instance.

Clean all residual artifacts, build OFBiz, and load default dataset. Since this is the first time running OFBiz, gradlew will download gradle and all build- and runtime dependencies needed by OFBiz, so it may take some time:

$ ./gradlew cleanAll loadDefault

If the build succeed, you can now start OFBiz instance:

$ ./gradlew ofbiz

You can also run OFBiz as background service:

$ ./gradlew ofbizBackground

Finally, to stop OFBiz after using it:

$ ./gradlew "ofbiz --shutdown"

systemd service

Most Linux systems/distributions are now run under systemd init system. It would be nice if OFBiz can be run automatically when system boots and stopped when system shuts down, without needing to login to ofbiz user and executing gradlew manually. This is where systemd service comes in.

Create /etc/systemd/system/ofbiz.service with following:

# OFBiz service

[Unit]
Description=OFBiz Service

[Service]
Type=simple

# environment variables
Environment="JAVA_HOME=/path/to/jdk8"
Environment="PATH=/path/to/jdk8/bin:/bin:/sbin:/usr/bin:/usr/sbin"

User=ofbiz
WorkingDirectory=/opt/ofbiz

# start and stop executables
# note that systemd requires specifying full/absolute path to executables
ExecStart=/opt/ofbiz/gradlew ofbiz
ExecStop=/opt/ofbiz/gradlew "ofbiz --shutdown"

[Install]
WantedBy=multi-user.target

Reload systemd daemon, then enable and start the service:

# systemctl daemon-reload
# systemctl enable ofbiz.service --now

The log, which is displayed to stdout when running gradlew manually, is now on systemd journal, which can be viewed by:

# journalctl -u ofbiz.service

Visit OFBiz from Your Browser

Head to Web Tools Administration on https://localhost:8443/webtools. You should see the page that instructs you to login with user admin and password ofbiz. If not, retrace the steps above to find out the cause of your problem and resolve it.

Conclusion

Now you have a working OFBiz instance on your system. In the next file in this gist, NGINX will serve OFBiz as reverse proxy. Stay tuned!

Serving OFBiz with NGINX as Reverse Proxy

Continuing from previous tutorial, Installing OFBiz, we will configuring NGINX to serve OFBiz instance by means of reverse proxy (that is, OFBiz will be put behind NGINX, and any requests to OFBiz instance will be passed from NGINX).

Prerequisites

  • You need to have OFBiz installed on your system. See Installing OFBiz for details.
  • A working NGINX setup. We assumed that you installed NGINX from the upstream's repository. You can consult online tutorials that discuss about NGINX configurations, but here we will only explain the ones that relevant for this tutorial.

Configuring OFBiz

From previous tutorial in this gist, OFBiz is installed to /opt/ofbiz. Change directory to it first (replace if you installed to different one):

$ cd /opt/ofbiz

By default, OFBiz use internal Tomcat server which is listening on any addresses (0.0.0.0). Because NGINX will sit in front of OFBiz, set listen address for Tomcat to only localhost.

Edit framework/base/ofbiz-component.xml. Set host property for JNDI naming server to 127.0.0.1, thus this name server only acts on localhost:

...
    <!-- load the naming (JNDI) server -->
    ...
        <property name="host" value="127.0.0.1"/>
    ...
...

When clients visit links on OFBiz, the permalinks generated points to the internal port (https://localhost:8443). In order to be served by NGINX, such permalinks must be rewritten without port (https://localhost).

Set serving port and domain names on framework/webapp/config/url.properties. Replace domain.tld with domain to be used to serve OFBiz:

...
port.https=443
force.https.host=domain.tld
...
port.http=80
force.http.host=domain.tld
...

Basic (All-Pass) NGINX Configuration

Now OFBiz have been configured for reverse-proxy support, we can move to NGINX setup. In this setup, all requests to OFBiz are proxy-passed from NGINX.

Create /etc/nginx/conf.d/ofbiz.conf with following:

# NGINX Reverse Proxy Configuration for OFBiz

# http
server {
    listen 80;
    listen [::]:80;

    server_name domain.tld;

    return 301 https://domain.tld$request_uri;
}

# https
server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name domain.tld;

    ssl_certificate     /path/to/your/site/certificate;
    ssl_certificate_key /path/to/your/site/certificate-private-key;

    location / {
        proxy_pass https://127.0.0.1:8443;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for;
    }
}

Serving Static Assets

In above setup, any requests (even static assets) are passed to OFBiz, which use embedded Tomcat HTTP server. However, this setup is somewhat heavy-weight as Tomcat does all actual request servings that proxied from NGINX. In this section, NGINX will be configured to directly serve static assets instead, and only pass to OFBiz if requested assets aren't found.

Again, edit /etc/nginx/conf.d/ofbiz.conf as following.

First, change location block from previous setup (location /) into named location block (location @ofbiz). This block will be referred when using try_files later as fallback location:

...
    location @ofbiz {
        proxy_pass https://127.0.0.1:8443;
        ...
    }
...

Add location block for static assets:

...
    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        root /opt/ofbiz/framework/images/webapp/images;
        try_files $uri $uri/ @ofbiz;
        expires 3d;
    }
...

Explanation: try_files are used to serve static assets, with @ofbiz as fallback location. In order for this to work, either set root directory globally (on server block context), or on location block (which we use here) first. Since static assets on OFBiz are on images webapp, the directory would be /opt/ofbiz/framework/images/webapp/images. Arguments to try_files specify that NGINX will look for requested assets on root directory first, before falling back to @ofbiz if not found. Expiry date for 3 days expires 3d; is also set, so that browsers can use their cached assets before re-requesting them for 3 days.

Finally, add location block that match root directory and files other than static assets:

...
    location / {
        root /opt/ofbiz/framework/images/webapp/images;
        try_files $uri $uri/ @ofbiz;
    }
...

Explanation: root directory and try_files arguments are same as for static assets above, without expires directive. You can put this block below static assets location block, so that location blocks for most specific URL are come first (in this case, location block for static assets is above location block for root).

Reload Server

After configuring NGINX as above, test for syntax errors:

# nginx -t

If no errors are found on your configuration, reload NGINX:

# nginx -s reload

Conclusion

Now you have NGINX serve your OFBiz Instance, and statics assets are served by NGINX, thus taking advantage of fast static content serving that NGINX offers.

This tutorial only cover basic working configurations that can be applied on almost any setups. Furthermore, when experimenting your configurations, always test for any performance bottlenecks and security holes. Whenever possible, prefer simplicity instead of fragile and untested configurations.

Full NGINX Configuration

# NGINX Reverse Proxy Configuration for OFBiz

# http
server {
    listen 80;
    listen [::]:80;

    server_name domain.tld;

    return 301 https://domain.tld$request_uri;
}

# https
server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name domain.tld;

    ssl_certificate     /path/to/your/site/certificate;
    ssl_certificate_key /path/to/your/site/certificate-private-key;

    location @ofbiz {
        proxy_pass https://127.0.0.1:8443;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        root /opt/ofbiz/framework/images/webapp/images;
        try_files $uri $uri/ @ofbiz;
        expires 3d;
    }

    location / {
        root /opt/ofbiz/framework/images/webapp/images;
        try_files $uri $uri/ @ofbiz;
    }
}

Credits

Using PostgreSQL as Database Backend for OFBiz

In this tutorial on this gist, we will configure OFBiz to use PostgreSQL, instead of embedded Derby (the default). Other ERP solutions like odoo and xTuple also database-backed by PostgreSQL.

Prerequisites

  • You need to have OFBiz built and installed on your system. If you don't have one, see Installing OFBiz for detailed installing guide.
  • Any supported version of PostgreSQL. You can either installing from your distribution or from upstream.

OFBiz Configuration

Change working directory to OFBiz directory. On Installing OFBiz, the directory is /opt/ofbiz. Substitute with your own path, if different:

$ cd /opt/ofbiz

In order for OFBiz to utilize PostgreSQL, some changes to entity engine (the component that handle data sources) are needed.

Edit framework/entity/config/entityconfig.xml as following:

  1. Set JDBC listen URI and credential details for both localpostgres, localpostolap, and localposttenant. On standard PostgreSQL installation, the listen address is localhost and port 5432. Default credentials for connection are ofbiz username and ofbiz password. Both username and password can be changed for security reasons, if you prefer.
...
<datasource name="localpostgres"
        ...>
    ...
    <inline-jdbc
            jdbc-driver="org.postgresql.Driver"
            jdbc-uri="jdbc:postgresql://127.0.0.1:5432/ofbiz"
            jdbc-username="ofbiz"
            jdbc-password="ofbiz" .../>
</datasource>
<datasource name="localpostolap"
        ...>
    ...
    <inline-jdbc
            jdbc-driver="org.postgresql.Driver"
            jdbc-uri="jdbc:postgresql://127.0.0.1:5432/ofbizolap"
            jdbc-username="ofbiz"
            jdbc-password="ofbiz" .../>
</datasource>
<datasource name="localposttenant"
        ...>
    ...
    <inline-jdbc
            jdbc-driver="org.postgresql.Driver"
            jdbc-uri="jdbc:postgresql://127.0.0.1:5432/ofbiztenant"
            jdbc-username="ofbiz"
            jdbc-password="ofbiz" .../>
</datasource>
...
  1. Configure delegators (default, default-no-eca, and test) to use PostgreSQL backend:
...
    <delegator name="default" entity-model-reader="main" entity-group-reader="main" entity-eca-reader="main" distributed-cache-clear-enabled="false">
        <group-map group-name="org.apache.ofbiz" datasource-name="localpostgres"/>
        <group-map group-name="org.apache.ofbiz.olap" datasource-name="localpostolap"/>
        <group-map group-name="org.apache.ofbiz.tenant" datasource-name="localposttenant"/>
    </delegator>
   <delegator name="default-no-eca" entity-model-reader="main" entity-group-reader="main" entity-eca-reader="main" entity-eca-enabled="false" distributed-cache-clear-enabled="false">
        <group-map group-name="org.apache.ofbiz" datasource-name="localpostgres"/>
        <group-map group-name="org.apache.ofbiz.olap" datasource-name="localpostolap"/>
        <group-map group-name="org.apache.ofbiz.tenant" datasource-name="localposttenant"/>
    </delegator>
    <delegator name="test" entity-model-reader="main" entity-group-reader="main" entity-eca-reader="main">
        <group-map group-name="org.apache.ofbiz" datasource-name="localpostgres"/>
        <group-map group-name="org.apache.ofbiz.olap" datasource-name="localpostolap"/>
        <group-map group-name="org.apache.ofbiz.tenant" datasource-name="localposttenant"/>
    </delegator>
...

Edit build.gradle to add build-time dependency to PostgreSQL JDBC driver. At the time writing this tutorial, the latest version is 42.2.8. See PostgreSQL JDBC homepage for latest version number and substitute below:

dependencies {
    ...
    compile 'org.postgresql:postgresql:42.2.8'
    ...
}

Database Setup

Switch user to system account for PostgreSQL:

# su postgres

Most commands below can be accomplished either by shell wrappers (prefixed by [postgres]$ wrapper-commands or by directly executing SQL queries from psql. Please choose one that convenient for you, as both method will be mentioned here.

Login to PostgreSQL if you don't use shell wrappers, as database superuser:

[postgres]$ psql

Create database user (role) to store OFBiz data. Ensure the credentials (username and password) match the ones specified on entity engine configuration above.

Shell Wrapper:

[postgres]$ createuser -l -P ofbiz

psql Query:

postgres=# CREATE ROLE ofbiz WITH NOCREATEDB LOGIN PASSWORD 'ofbiz'

Create ofbiz, ofbizolap, and ofbiztenant databases and own them to ofbiz role. Set encoding for both databases to UTF-8. It also use template0 as template database from which to create them in order to circumvent locale errors (as template0 doesn't contain any locale-specific informations).

Shell Wrapper:

[postgres]$ createdb -O ofbiz -E UTF8 -T template0 ofbiz
[postgres]$ createdb -O ofbiz -E UTF8 -T template0 ofbizolap
[postgres]$ createdb -O ofbiz -E UTF8 -T template0 ofbiztenant

psql Query:

postgres=# CREATE DATABASE ofbiz WITH OWNER ofbiz TEMPLATE template0 
ENCODING 'UTF8';
postgres=# CREATE DATABASE ofbizolap WITH OWNER ofbiz TEMPLATE template0 
ENCODING 'UTF8';
postgres=# CREATE DATABASE ofbiztenant WITH OWNER ofbiz TEMPLATE template0 
ENCODING 'UTF8';

Database Authentication

In order for OFBiz to be able to load data into the database, ofbiz database user specified in the database must successfully connected to the database by password authentication. To do this, configure authentication by password by editing pg_hba.conf and postgresql.conf

However, depending on your PostgreSQL version and your distribution, full path to those files can be different. Find them by:

# find / -type f -name pg_hba.conf
# find / -type f -name postgresql.conf

On CentOS 7 with PostgreSQL 11 installed from upstream's repository, the full paths are /var/lib/pgsql/11/data/pg_hba.conf and /var/lib/pgsql/11/data/postgresql.conf, respectively. Please substitute with your own paths.

PostgreSQL supports MD5 and SHA-256 for encrypted password authentication. However, the MD5 algorithm (default option) is weak and insecure. For security reasons, configure PostgreSQL to use SCRAM SHA-256 when using password authentication.

Edit pg_hba.conf and change authentication method for local connections to SCRAM SHA-256:

...
# IPv4 local connections:
host    all             all             127.0.0.1/32            scram-sha-256
# IPv6 local connections:
host    all             all             ::1/128                 scram-sha-256
...

Also edit postgresql.conf so that SHA-256 password authentication is used:

...
password_encryption = scram-sha-256
...

Restart PostgreSQL service. For example, on above distribution setup:

# systemctl restart postgresql-11.service

For other distributions and setups, you can find the service name by:

# systemctl list-units | grep postgresql

Password for users (ofbiz in this case) are still stored in MD5 hash. Reassign password to the user so that it stored in SHA-256. Make sure the password assigned is same as the one specified in entity engine:

postgres=# ALTER ROLE ofbiz WITH PASSWORD 'ofbiz';

Rebuild OFBiz

After configuring both PostgreSQL and OFBiz, rebuild the latter by clean previous build, load data into PostgreSQL and start the server:

$ cd /opt/ofbiz
$ ./gradlew cleanAll loadDefault
$ ./gradlew ofbiz

Depending on your system specification and load, the build process time can took 2 to 5 times faster than when using Derby. Such a nice time savings!

Conclusion

Now you have PostgreSQL back your OFBiz instance. This is only tip of iceberg: you can add more sophisticated setups (like replication) for high availability.

This concludes OFBiz Setup Guides. Hope that guides given to you will be useful to your setup. Happy Open for Business!

@sandjay75
Copy link

Clean and useful. Thank you very much .

@deleuzei
Copy link

deleuzei commented Jan 1, 2023

JDK 11 works on Debian 10. The later versions don't. You also have to run first ./gradle/init-gradle-wrapper.sh as documented in the official guide

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment