With the host tuned, we now give APEX a home. This tutorial creates a dedicated pluggable database called APEX_PDB, lays down four tablespaces for it (Phase 3), then runs the APEX 26.1 installer into that PDB and publishes its static images (Phase 4). At the end you have a working APEX engine - schema APEX_260100 - waiting for a middle tier to put in front of it.
This is the third tutorial in the series. It assumes you have finished Tutorial 01: a tuned AlmaLinux 9 host running Oracle 26ai, with the container database ORCLCDB sized for the workload. As before, hostnames, paths, and the schema passwords shown are placeholders - swap in your own.
Phase 3 - Create APEX_PDB and tablespaces
Oracle's multitenant architecture lets one container database (CDB) host many pluggable databases (PDBs). A PDB is a self-contained database with its own schemas, users, and tablespaces, but it shares the CDB's memory and background processes. The payoff here is isolation: putting APEX in its own PDB keeps it cleanly separated from any other workload on the same instance. You can open, close, clone, or unplug it on its own.
We also give it four purpose-built tablespaces rather than dumping everything in USERS. APEX_DATA holds tables, APEX_APP holds application objects, APEX_IDX holds indexes only, and APEX_TEMP is the temporary tablespace. Separating indexes from data onto their own tablespace is a long-standing way to spread I/O.
Create the PDB
Connect as sysdba to the CDB and create the pluggable database. The FILE_NAME_CONVERT clause copies the seed database's files into a new apex_pdb directory, giving the PDB its own datafiles. After creation we open it and save that open state so it reopens automatically when the instance restarts.
CREATE PLUGGABLE DATABASE APEX_PDB
ADMIN USER apex_pdb_admin IDENTIFIED BY "ApexPdb@Adm1n!"
ROLES = (DBA)
DEFAULT TABLESPACE USERS
DATAFILE '/opt/oracle/oradata/ORCLCDB/apex_pdb/users01.dbf'
SIZE 100M AUTOEXTEND ON NEXT 100M MAXSIZE 2G
FILE_NAME_CONVERT = (
'/opt/oracle/oradata/ORCLCDB/pdbseed/',
'/opt/oracle/oradata/ORCLCDB/apex_pdb/'
);
ALTER PLUGGABLE DATABASE APEX_PDB OPEN;
ALTER PLUGGABLE DATABASE APEX_PDB SAVE STATE;
The ApexPdb@Adm1n! password is illustrative - use a real secret. Without SAVE STATE the PDB would come up MOUNTED rather than OPEN after a restart, and APEX would be unreachable until someone opened it by hand.
Connect to APEX_PDB and create the tablespaces
Now connect directly into the PDB, not the CDB root. The service name in the connect string is what routes you into APEX_PDB.
sqlplus sys@localhost:1521/APEX_PDB as sysdba
Create the four tablespaces. Notice the differences: data and app tablespaces start large and autoextend in big steps, the index tablespace uses a smaller uniform extent size (256K) because index segments tend to be smaller, and APEX_TEMP is created as a temporary tablespace and then made the database default temporary tablespace.
CREATE TABLESPACE APEX_DATA
DATAFILE '/opt/oracle/oradata/ORCLCDB/apex_pdb/apex_data01.dbf'
SIZE 1G AUTOEXTEND ON NEXT 512M MAXSIZE 20G
EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1M
SEGMENT SPACE MANAGEMENT AUTO LOGGING;
CREATE TABLESPACE APEX_APP
DATAFILE '/opt/oracle/oradata/ORCLCDB/apex_pdb/apex_app01.dbf'
SIZE 2G AUTOEXTEND ON NEXT 512M MAXSIZE 30G
EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1M
SEGMENT SPACE MANAGEMENT AUTO LOGGING;
CREATE TABLESPACE APEX_IDX
DATAFILE '/opt/oracle/oradata/ORCLCDB/apex_pdb/apex_idx01.dbf'
SIZE 512M AUTOEXTEND ON NEXT 256M MAXSIZE 10G
EXTENT MANAGEMENT LOCAL UNIFORM SIZE 256K
SEGMENT SPACE MANAGEMENT AUTO LOGGING;
CREATE TEMPORARY TABLESPACE APEX_TEMP
TEMPFILE '/opt/oracle/oradata/ORCLCDB/apex_pdb/apex_temp01.dbf'
SIZE 1G AUTOEXTEND ON NEXT 512M MAXSIZE 8G
EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1M;
ALTER DATABASE DEFAULT TEMPORARY TABLESPACE APEX_TEMP;
All four datafiles land in the PDB's own directory under /opt/oracle/oradata/ORCLCDB/apex_pdb/, keeping its storage self-contained.
Phase 4 - Install APEX 26.1
The APEX installer, apexins.sql, creates every APEX schema - APEX_260100, APEX_PUBLIC_USER, FLOWS_FILES, and the rest - inside the PDB. It is a long job, 20 to 40 minutes, and it must not be interrupted. We run it as the oracle OS user, connected straight into APEX_PDB rather than the CDB root, so the engine installs in the isolated container we just built and not across the whole instance.
Run the install connected to APEX_PDB, never the CDB root. Installing into the root would push APEX into every PDB through the application container mechanism, which is not what we want for a single dedicated APEX database.
Prepare the files
As root, unpack the APEX distribution under the Oracle base and hand ownership to the oracle account.
mkdir -p /opt/oracle/apex
unzip /tmp/apex_26.1_en.zip -d /opt/oracle
chown -R oracle:oinstall /opt/oracle/apex
Run the installation as the oracle user
Switch to the oracle user, change into the APEX directory, and connect to the PDB.
cd /opt/oracle/apex
sqlplus sys@localhost:1521/APEX_PDB as sysdba
The installer takes four parameters in order: the tablespace for APEX metadata, the tablespace for files, the temporary tablespace, and the images URL path. Here that is APEX_DATA, APEX_DATA, APEX_TEMP, and /i/. After the main install finishes, apxchpwd.sql sets the APEX internal administrator password, apex_rest_config.sql configures REST services, and then we unlock and set passwords on the three service accounts ORDS needs to talk to the database.
-- Main installation (20-40 min - do not interrupt)
@apexins.sql APEX_DATA APEX_DATA APEX_TEMP /i/
-- After install completes: set admin password
@apxchpwd.sql
-- Configure REST services
@apex_rest_config.sql
-- Unlock and set passwords on ORDS service accounts
ALTER USER APEX_PUBLIC_USER ACCOUNT UNLOCK;
ALTER USER APEX_PUBLIC_USER IDENTIFIED BY "ApexPub1ic!";
ALTER USER APEX_REST_PUBLIC_USER ACCOUNT UNLOCK;
ALTER USER APEX_REST_PUBLIC_USER IDENTIFIED BY "ApexR3stPub!";
ALTER USER APEX_LISTENER ACCOUNT UNLOCK;
ALTER USER APEX_LISTENER IDENTIFIED BY "ApexL1st3n!";
Those three accounts - APEX_PUBLIC_USER, APEX_REST_PUBLIC_USER, and APEX_LISTENER - are locked by default after install. ORDS authenticates as them, so they must be unlocked and given known passwords now. The passwords shown are placeholders; record your real ones, because Tutorial 03 feeds them to the ORDS installer.
Copy the APEX images to the Apache web root
APEX serves its CSS, JavaScript, and images as static files under the /i/ URL path. Rather than route that traffic through the database, we copy the image set to a directory Apache can serve directly.
mkdir -p /var/www/apex/images
cp -R /opt/oracle/apex/images/* /var/www/apex/images/
chown -R apache:apache /var/www/apex/images
chmod -R 755 /var/www/apex/images
In 26.1 the static image path version moves with each release and is served at /i/. Keep the Apache /i alias pointed at this copy so it always matches the installed APEX build - a mismatch shows up as an unstyled, broken-looking APEX login page.
What you have now: a dedicated APEX_PDB with four tablespaces, the APEX 26.1 engine installed as schema APEX_260100, REST configured, the ORDS service accounts unlocked, and the static images staged for Apache. The database tier is complete. Next, in Tutorial 03, we build the middle tier - Oracle JDK 21, Tomcat 9.0.117, and ORDS 26.1.0 - to turn web requests into calls against this engine.