oracle-apex-docker

Install & Run Oracle APEX in a Docker Environment

Docker Docker-Compose Oracle Oracle-APEX

Why This Repository

So far, with the manuals both on Oracle’s website as well as the ones found on blogs etc. I never really succeeded in putting up the APEX stack on docker.

However, starting to try with some more (docker) experience after procrastinating APEX in the recent 3 years, and with new energy, I found some key hints to get it done.

Content

This docker project contains the following:

TL;DR

Here’s the recipe to get this done:

  1. Create folders
  2. Initialize Express DB
  3. Setup APEX in the Express DB
  4. Download APEX files
  5. Create & Run Docker Compose
  6. Optional: Access APEX from WAN with HTTPS / Reverse Proxy

Detailed Instructions

0 - Prerequisites

Image Sources

I wanted to use the following images:

The ords-developer image does not contain and install APEX, but there’s a solution.

Naming Conventions

A few remarks about the names of objects: I generally try to name docker containers, networks etc. by using prefixes so I can identify them easier in, e.g., lists (docker ls ...) or when searching for their repositories (directories).

In this context, rad is short for Rapid Application Development, and, since there are several platforms, oracle-apex is the second prefix. expressand ords are then the specifying parts of the name.

In the case of docker service names, I use only express and ords because those service names are referred to only within the compose file.

1 - Prepare Directories For Persistent Data & Define Parameters :heavy_check_mark:

Start in the docker project’s direcctory. According to Oracle, the following rights have to be applied to the directory ./express/oradata:

-v /opt/oracle/oradata
                  The data volume to use for the database.
                  Has to be writable by the Unix "oracle" (uid: 54321) user inside the container.
                  If omitted the database will not be persisted over container recreation.

Folders for Express & ORDS :heavy_check_mark::heavy_check_mark:

sudo bash -c '
  mkdir -p ./express/{oradata,cfgtoollogs,scripts/startup,scripts/setup} && 
  chown -R 54321:54321 ./express/{oradata,cfgtoollogs} &&
  mkdir -p ./ORDS/{variables,config} &&
  chown -R 54321:54321 ./ORDS/{config,variables} &&
  chmod -R 777 ./ORDS/config
'

The cfgtoollogs-diretory is for analysis in case of database creation failure (./cfgtoollogs/dbca/XE/XE.log).

.env File

Create .env file containing a ORACLE_PWD variable and a password (do not use special characters, only numbers, small and caps for compatibility reasons; Oracle recommends that the password entered should be at least 8 characters in length, contain at least 1 uppercase character, 1 lower case character and 1 digit [0-9]. Note that the same password will be used for SYS, SYSTEM and PDBADMIN accounts):

ORACLE_PWD=<password without quotes of any kind>, e.g., 1230321abcABC.

Script: :heavy_check_mark::heavy_check_mark:

#!/bin/bash

# Prompt user for ORACLE_PWD
read -p "Enter a value for ORACLE_PWD: " ORACLE_PWD

# Write the variable to .env file
echo "ORACLE_PWD=$ORACLE_PWD" > ./.env

echo "Password has been written to ./.env"

2 - Download & Extract APEX Files :heavy_check_mark::heavy_check_mark:

Download and extract the latest APEX files to the project directory; the APEX ZIP file contains the apex directory as root, so no extra dir has to be created.

If you have unzip: :heavy_check_mark::heavy_check_mark:

curl -o apex.zip https://download.oracle.com/otn_software/apex/apex-latest.zip && \
unzip -o apex.zip

If you have 7z (e.g., Synology NAS): :heavy_check_mark::heavy_check_mark:

curl -o apex.zip https://download.oracle.com/otn_software/apex/apex-latest.zip && \
7z x apex.zip

The files should now reside in ./apex.

3 - Pull Docker Images :heavy_check_mark::heavy_check_mark:

Option 1 - loop :heavy_check_mark::heavy_check_mark:

for img in express ords; do
  docker pull "container-registry.oracle.com/database/$img:latest"
done

Option 2 - xargs

echo "container-registry.oracle.com/database/"{express,ords}":latest" \
  | xargs -n1 docker pull

4 - Create & Run Temporary Express Container to Setup Persistent DB :heavy_check_mark::heavy_check_mark:

Run the following command to :heavy_check_mark::heavy_check_mark:

docker network create rad-oracle-apex-temp & \
docker run \
    -d \
    --name rad-oracle-apex-express-temp \
    --network rad-oracle-apex-temp \
    --hostname express \
    --env-file ./.env \
    -p 1521:1521 \
    -v "$(pwd)/express/oradata/:/opt/oracle/oradata" \
    -v "$(pwd)/express/cfgtoollogs/:/opt/oracle/cfgtoollogs" \
    -v "$(pwd)/apex/:/opt/oracle/oradata/apex" \
    container-registry.oracle.com/database/express:latest && \
docker logs -f rad-oracle-apex-express-temp

[!NOTE]

grafik grafik

[!IMPORTANT] If the first time fails, a second run with the code above might solve it.

Keep the container running for the next steps of the installation (until you start the containers with docker-compose).

5 - Install APEX :heavy_check_mark:

Download APEX :heavy_check_mark:

Already done in the preparation steps above.

Install APEX in the Express DB :heavy_check_mark:

  1. Create a shell in the express container:
    docker exec -it rad-oracle-apex-express-temp bash
    
  2. Change to the mounted apex directory:
    cd /opt/oracle/oradata/apex
    
  3. Connect to the DB XEPDB1:
    • In separate steps:
      1. Start SQL:
        sqlplus /nolog
        

        (note that unlike described in the documentation, steps 4 and 6, instead of sql, sqlplus is used)

      2. Connect to DB XEPDB1:
        • With extra PW prompt:
          1. CONNECT SYS@<express hostname>:1521/XEPDB1 as SYSDBA
            
          2. enter PW (defined in .env-file)
        • With PW in command:
          CONNECT SYS/<ORACLE_PWD>@<express hostname>:1521/XEPDB1 as SYSDBA
          
    • In single step:
      cd /opt/oracle/oradata/apex && sqlplus sys/${ORACLE_PWD}@<express hostname>:1521/XEPDB1 AS SYSDBA
      

      e.g.,

      cd /opt/oracle/oradata/apex && sqlplus sys/${ORACLE_PWD}@express:1521/XEPDB1 AS SYSDBA
      

      (note that ${ORACLE_PWD} does not have to be replaced here since taken from the environment variable in this case; also, this will be used for the CONN_STRING file below, but there, ORACLE_PWD needs to be explicit)

  4. Run install script: @apexins.sql SYSAUX SYSAUX TEMP /i/ After successful installation, leave SQL open for the next step

Final Preparations

  1. Create the Instance Administration Account: In the same SQL prompt as before, enter
    @apxchpwd.sql
    

    to create the workspace admin account.

  2. Unlock APEX_PUBLIC_USER account: In the same SQL prompt as before, enter
    ALTER USER APEX_PUBLIC_USER ACCOUNT UNLOCK;
    
  3. Change password (optional?):
    ALTER USER APEX_PUBLIC_USER IDENTIFIED BY <new_password>;
    
  4. Unlimit account expiration: From a blog post:
    1. Create unlimited expiration profile apex_public:
      create profile apex_public limit
        password_life_time unlimited;
      
    2. Assign profile to user:
      alter user apex_public_user
        profile apex_public;
      
        - `quit` the SQL prompt
        - `exit` the container's bash
      

6 - Run Temporary ORDS-Developer Container to Setup the Connection to the Express DB :heavy_check_mark::heavy_check_mark:

[!NOTE] Things have changed since release of ORDS v25. A container can be started in 2 ways:

grafik

7 - Remove Temporary Containers :heavy_check_mark::heavy_check_mark:

docker rm -f rad-oracle-apex-{ords-temp,express-temp}

8 - Run APEX with Docker Compose :heavy_check_mark::heavy_check_mark:

services:
  express: # XE database
    image: container-registry.oracle.com/database/express:latest # 21.3.0-xe
    container_name: rad-oracle-apex-express
    # hostname: oracledev
    restart: unless-stopped
    environment:
      - ORACLE_PWD=${ORACLE_PWD} # make sure the declaration is in the .env file as ORACLE_PWD=<your password, non complex, min. 8 chars small, cap, & numbers>
    networks:
      - apex
    #ports:
    #  - 1521:1521
    #  - 5500:5500
    # depends_on:
    #   - oracle-ords
    volumes:
      - ./express/oradata:/opt/oracle/oradata
      - ./express/scripts/setup:/opt/oracle/scripts/setup
      - ./express/scripts/startup:/opt/oracle/scripts/startup
      - ./apex:/opt/oracle/apex
    healthcheck:
      #test command below is with grep because in my case, the output of checkDBstatus.sh is always "The Oracle base remains unchanged with value /opt/oracle" which seems to indicate the DB is fine.
      #test: /opt/oracle/checkDBStatus.sh | grep -q 'remains unchanged'
      test: [ "CMD", "/opt/oracle/checkDBStatus.sh"]
      interval: 30s
      timeout: 30s
      retries: 100
      start_period: 600s

  ords:
    #image: container-registry.oracle.com/database/ords-developer:latest
    image: container-registry.oracle.com/database/ords:latest
    container_name: rad-oracle-apex-ords
    restart: unless-stopped
    #depends_on:
    #  express:
    #    condition: service_healthy
    volumes:
      - ./ORDS/variables:/opt/oracle/variables
      - ./ORDS/config:/etc/ords/config
      - ./apex/:/opt/oracle/apex
    networks:
      - apex
    ports:
    #- 8181:8181 this is for the developer image
    - 8080:8080

networks:
  apex:
    name: rad-oracle-apex

In case you want to debug the healthcheck, use docker inspect --format "" rad-oracle-apex-express | jq:

grafik

Once the express-container has started up, the exit code changes from 3 over 2 to 0 (0=healthy).

9 - Log In

APEX Workspace

  1. Go to your instance’s APEX homepage, e.g., http://<docker-host>.
  2. Select Oracle APEX (the middle pane)
  3. Login:
    • Workspace: internal
    • User: ADMIN
    • Password: Welcome_1

[!WARNING] If you changed the password during log-in check from running the temporary ORDS-Developer container, use the updated password!

APEX Administration

  1. Go to your instance’s APEX homepage, e.g., http://<docker-host>.
  2. Select Oracle APEX (the middle pane)
  3. Go to the bottom of the page and select Administration in the Tasks column
  4. Login:
    • User: admin
    • Password: The one you changed the default password Welcome_1 to

SQL Developer Web (SDW): Set Up & Log In

Well, that’s a whole different story: The workspace/database schema needs to be enabled for SDW as follows:

  1. Log into the express container’s CLI:
    • To get to the SQL prompt directly: docker exec -it oracle-apex-express sqlplus sys/<ORACLE_PWD>@//localhost:1521/XEPDB1 as sysdba
    • Via shell: docker exec -it oracle-apex-express sh and then enter sqlplus sys/<ORACLE_PWD>@//localhost:1521/XEPDB1 as sysdba at the prompt
  2. Now, the following must be entered:
    BEGIN
     ords_admin.enable_schema(
      p_enabled => TRUE,
      p_schema => 'schema-name',
      p_url_mapping_type => 'BASE_PATH',
      p_url_mapping_pattern => 'schema-alias',
      p_auto_rest_auth => NULL
     );
     commit;
    END;
    /
    

    [!IMPORTANT]

    E.g.,

    BEGIN
     ords_admin.enable_schema(
      p_enabled => TRUE,
      p_schema => 'WORKSPACE1',
      p_url_mapping_type => 'BASE_PATH',
      p_url_mapping_pattern => 'workspace1',
      p_auto_rest_auth => NULL
     );
     commit;
    END;
    /
    
  3. Optional: Verify if schema (= value used for p_schema) has been enabled with select username from all_users order by username
  4. Change user password via SQL prompt: alter user <user> identified by <password>; (replace <user) - every workspace, in the database, is basically a user, hence this step
  5. Go to http(s)://<domain name>/ords/sql-developer and log in with the credentials used above

[!WARNING] There seems to be a bug in ORDS which prevents objects from loading in SDW’s Data Modeler and SQL Navigator. The DB user (equals workspace name) therefore needs to be granted resource permissions as follows:

grant <privilege> to <user>

This solution might work, with me, it didn’t. However, the ORDS update from Nov. 8, 2024, solved the issue.

10 - Access APEX from WAN with HTTPS / Reverse Proxy

Put the following 2 lines into ./ORDS/config/global/settings.xml, replacing <your apex domain, no trailing slash> with your domain’s name:

<entry key="security.externalSessionTrustedOrigins">http://<your apex domain, no trailing slash>, https://<your apex domain, no trailing slash>:443</entry>
<entry key="security.forceHTTPS">true</entry>

The complete settings.xml might now look similar to:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>Saved on Mon Oct 21 16:07:13 UTC 2024</comment>
<entry key="database.api.enabled">true</entry>
<entry key="db.invalidPoolTimeout">5s</entry>
<entry key="debug.printDebugToScreen">true</entry>
<entry key="standalone.static.path">/opt/oracle/apex/images</entry>
<entry key="security.externalSessionTrustedOrigins">http://<your apex domain, no trailing slash>, https://<your apex domain, no trailing slash>:443</entry>
<entry key="security.forceHTTPS">true</entry>
</properties>

11 - Update

APEX

Update ORDS

ORDS has been released in a v25. In order to configure the ORDS images (starting with v25), run a container and start the bash:

docker run -it --name ords_new -v ./ORDS/config:/etc/ords/config container-registry.oracle.com/database/ords:latest <command>

E.g.,

docker run -it --name ords_new -v ./ORDS/config:/etc/ords/config container-registry.oracle.com/database/ords:latest install

Docker Installation Sources

Sources used for new attempt

Sources used years ago

… and a few more.

APEX Programming

Integration With 3rd Party Tools

  1. See also https://docs.oracle.com/en/database/oracle/oracle-database/21/sqpug/slash.html