Pages

Oracle 19c/23c Multi-Home & 2-Node RAC

Oracle Linux 8 | Run 19c + 23c Together | Production RAC Setup

Want to run stable 19c production alongside cutting-edge 23c testing? Add bulletproof 2-node RAC? This guide has you covered—multi-home magic, Grid Infrastructure, SCAN, rolling patches, everything.

Why Multi-Home Rocks
/u01/app/oracle/
├── product/19.0.0/dbhome_1     ← LTS Production
├── product/23.0.0/dbhome_1     ← Innovation Testing
└── oraInventory                ← Shared

Benefits:
  • Zero-downtime feature testing
  • Safe rolling migration path
  • Independent patching cycles
  • Separate listeners (1521 vs 1522)
1. Quick OS Check
ulimit -n  # Should be ≥ 65536
ulimit -u  # Should be ≥ 16384

# Fix if needed
echo "oracle soft nofile 65536" | sudo tee -a /etc/security/limits.conf
echo "oracle hard nofile 65536" | sudo tee -a /etc/security/limits.conf

2. Enterprise Groups
sudo groupadd -g 20011 backupdba
sudo groupadd -g 20012 dgdba  
sudo groupadd -g 20013 kmdba
sudo groupadd -g 20014 asmdba
sudo groupadd -g 20015 asmoper
sudo groupadd -g 20016 asmadmin

sudo usermod -a -G backupdba,dgdba,kmdba,asmdba,asmoper,asmadmin oracle

3. Install 23c Alongside 19c (Silent)
# Create 23c home
sudo mkdir -p /u01/app/oracle/product/23.0.0/dbhome_1
sudo chown oracle:oinstall /u01/app/oracle/product/23.0.0
sudo chmod 775 /u01/app/oracle/product/23.0.0 -R

su - oracle
cd /u01/app/oracle/product/23.0.0/dbhome_1
unzip LINUX.X64_230000_db_home.zip

export ORACLE_HOME=/u01/app/oracle/product/23.0.0/dbhome_1
export ORACLE_BASE=/u01/app/oracle
export CV_ASSUME_DISTID=OEL8.1

./runInstaller -silent -waitforcompletion \
-responseFile $ORACLE_HOME/install/response/db_install.rsp \
oracle.install.option=INSTALL_DB_SWONLY \
ORACLE_HOME=$ORACLE_HOME \
ORACLE_BASE=$ORACLE_BASE \
oracle.install.db.InstallEdition=EE \
oracle.install.db.OSDBA_GROUP=dba \
oracle.install.db.OSBACKUPDBA_GROUP=backupdba \
oracle.install.db.OSDGDBA_GROUP=dgdba \
oracle.install.db.OSKMDBA_GROUP=kmdba \
DECLINE_SECURITY_UPDATES=true

# Root scripts
sudo $ORACLE_HOME/root.sh

4. Smart Listener Strategy
Separate listeners = no conflicts:

19c: LISTENER on port 1521
23c: LISTENER23 on port 1522

# 23c listener.ora
cat > $ORACLE_HOME/network/admin/listener.ora <<EOF
LISTENER23 =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = $(hostname))(PORT = 1522))
    )
  )
EOF

lsnrctl start LISTENER23

5. Create 23c CDB+PDB
export ORACLE_SID=cdb23
dbca -silent -createDatabase \
-gdbname cdb23 -sid cdb23 \
-createAsContainerDatabase true \
-numberOfPDBs 1 -pdbName pdb23 \
-characterSet AL32UTF8 \
-totalMemory 4096 \
-storageType FS \
-datafileDestination "/u02/oradata23"

6. RAC Network Setup (Both Nodes)
/etc/hosts:
192.168.10.11  node1.localdomain  node1
192.168.10.12  node2.localdomain  node2  
192.168.10.13  node1-vip.localdomain  node1-vip
192.168.10.14  node2-vip.localdomain  node2-vip
192.168.10.15  cluster-scan.localdomain  cluster-scan

Public + Private + VIP + SCAN = 4 networks needed.

7. ASM Shared Storage (Both Nodes)
# Install ASM packages
sudo dnf install -y oracleasm-support oracleasmlib oracleasm

# Configure
sudo oracleasm configure -i
sudo oracleasm init

# Create disks (run on both nodes)
sudo oracleasm createdisk DATA01 /dev/sdb1
sudo oracleasm createdisk FRA01 /dev/sdc1
oracleasm listdisks

8. Grid Infrastructure (Node 1 Only)
sudo mkdir -p /u01/app/19.0.0/grid
sudo chown oracle:oinstall /u01/app/19.0.0/grid
sudo chmod 775 /u01/app/19.0.0/grid

su - oracle
cd /u01/app/19.0.0/grid
unzip LINUX.X64_193000_grid_home.zip

./runInstaller -silent -waitforcompletion \
-oracle.install.option=CRS_CONFIG \
-CLUSTER_NODES=node1,node2 \
-oracle.install.asm.OSASM=asmadmin \
-oracle.install.asm.OSDBA=asmdba \
-oracle.install.asm.OSOPER=asmoper \
-ASM_DISKSTRING="/dev/oracleasm/disks/*" \
-WAIT_FOR_COMPLETION=YES
Run root scripts on BOTH nodes when prompted.

9. Create RAC Database
dbca -silent -createDatabase \
-databaseType RAC \
-gdbname racdb -sid racdb \
-nodeList node1,node2 \
-storageType ASM \
-diskGroupName DATA \
-createAsContainerDatabase true \
-numberOfPDBs 1 -pdbName pdb1 \
-totalMemory 4096

10. RAC Services (Load Balancing)
# Apps service (node1 preferred, node2 available)
srvctl add service -db racdb \
-service appsvc \
-preferred racdb1 \
-available racdb2

srvctl start service -db racdb -service appsvc

11. Rolling Patch Magic
# Check cluster health
crsctl check cluster -all

# Patch node1 only
srvctl stop instance -db racdb -instance racdb1
$ORACLE_HOME/OPatch/opatch apply
srvctl start instance -db racdb -instance racdb1

# Verify
srvctl status database -d racdb
Zero downtime = happy users.

12. RAC Health Dashboard
# One-liner cluster status
echo "=== CLUSTER ==="; crsctl stat res -t | grep racdb
echo "=== DATABASE ==="; srvctl status database -d racdb -v  
echo "=== NODES ==="; olsnodes -n
echo "=== SCAN ==="; srvctl config scan

# Global Cache (should be <5% DB time)
sqlplus / as sysdba <<EOF
SELECT inst_id, name, value FROM gv\$sysstat WHERE name LIKE 'gc%';
SELECT * FROM gv\$cluster_interconnects;
EOF

13. Multi-Home Switching
Use oraenv magic:
. oraenv  # Prompts: ORACLE_SID = [cdb1] ? cdb23
# Switches PATH, LD_LIBRARY_PATH automatically

Or manual:
# 19c
export ORACLE_HOME=/u01/app/oracle/product/19.0.0/dbhome_1
export ORACLE_SID=cdb1

# 23c  
export ORACLE_HOME=/u01/app/oracle/product/23.0.0/dbhome_1
export ORACLE_SID=cdb23

14. Production Validation Matrix
EnvironmentExpectedCommand
19c Singlecdb1 - OPENsrvctl status database -d cdb1
23c Singlecdb23 - OPENsrvctl status database -d cdb23
RAC2 instancessrvctl status database -d racdb
ASMDATA + FRA MOUNTEDasmcmd lsdg
SCAN3 IPs resolvingnslookup cluster-scan

15. Security Hardening
# RAC-specific
sqlplus / as sysdba
ALTER SYSTEM SET REMOTE_LISTENER='cluster-scan:1521';
ALTER SYSTEM SET LOCAL_LISTENER='(ADDRESS=(PROTOCOL=TCP)(HOST=node1)(PORT=1521))';

# Valid node checking
lsnrctl <<EOF
SET CURRENT_LISTENER listener
CHANGE PASSWORD sys/password
SAVE_CONFIG
EOF

Oracle 19c/23c Enterprise Ops: ASM, RMAN, Data Guard & RAC Monitoring

This guide builds bulletproof Oracle infrastructure for banking, telecom, government—systems that can't go down. Zero data loss, automated everything, online patching ready.

Architecture Goals
  • 99.99% uptime (26 minutes downtime/year max)
  • Zero data loss (MAXIMUM PROTECTION Data Guard)
  • <4hr backup windows
  • Online patching & rolling upgrades
  • Performance baselines with alerting
1. ASM: Your Storage Foundation
1.1 Redundancy Cheat Sheet
RedundancyMirrorsWhen to Use
EXTERNALNoneStorage arrays handle it (e.g., SAN)
NORMAL2xStandard production (most common)
HIGH3xMission-critical, no single failure tolerated

1.2 Create ASM Disks
Never use dd in production. Use parted:
# For each disk (/dev/sdb, sdc, etc.)
$ sudo parted /dev/sdb mklabel gpt
$ sudo parted /dev/sdb mkpart primary 1MiB 100%

# Create ASM disks
$ oracleasm createdisk DATA01 /dev/sdb1
$ oracleasm createdisk DATA02 /dev/sdc1
$ oracleasm createdisk FRA01 /dev/sdd1
$ oracleasm createdisk FRA02 /dev/sde1
$ oracleasm listdisks  # Verify

1.3 Create Diskgroups
# DATA (8TB, NORMAL redundancy)
$ asmca -silent -createDiskGroup -diskGroupName DATA -disk '/dev/oracleasm/disks/DATA*' -redundancy NORMAL -au_size 4

# FRA (4TB backup/recovery)
$ asmca -silent -createDiskGroup -diskGroupName FRA -disk '/dev/oracleasm/disks/FRA*' -redundancy NORMAL

Pro tip: Separate DATA/FRA = no backup I/O contention.

1.4 Monitor Rebalance
-- Check progress
SELECT * FROM v$asm_operation;

-- Speed up (1-11, default=1)
ALTER DISKGROUP DATA REBALANCE POWER 8;

1.5 Failure Groups
CREATE DISKGROUP DATA NORMAL REDUNDANCY
FAILGROUP rack1 DISK '+DATA/DATA01'
FAILGROUP rack2 DISK '+DATA/DATA02';

2. RMAN: Enterprise Backup Mastery
2.1 Block Change Tracking (10x Faster Incrementals)
ALTER DATABASE ENABLE BLOCK CHANGE TRACKING USING FILE '+DATA/bct.dbf';
SELECT status FROM v$block_change_tracking;  -- SHOULD_READ
2.2 RMAN Catalog (Mandatory for Enterprise)

Recovery Catalog DB (separate small DB):
rman catalog rman/secret@catdb
REGISTER DATABASE;

2.3 Incremental Forever Strategy
Weekly full → Daily incrementals → Merge image copy:
RUN {
  RECOVER COPY OF DATABASE WITH TAG 'incr_update';
  BACKUP INCREMENTAL LEVEL 1 FOR RECOVER OF COPY 
    WITH TAG 'incr_update' DATABASE;
}

Benefits: 30min backups, instant point-in-time recovery.

2.4 Validate Everything
RESTORE DATABASE VALIDATE;
BACKUP VALIDATE DATABASE ARCHIVELOG ALL;

2.5 Quarterly Restore Drill
RUN {
  SET UNTIL TIME "SYSDATE-1";
  RESTORE DATABASE;
  RECOVER DATABASE;
}

Document your RTO/RPO results.

3. Data Guard Broker
3.1 Broker Setup
ALTER SYSTEM SET dg_broker_start=TRUE;
$ dgmgrl sys/secret
DGMGRL> CREATE CONFIGURATION 'DGCONFIG' AS 
         PRIMARY DATABASE IS 'racdb' CONNECT IDENTIFIER IS racdb;
DGMGRL> ADD DATABASE 'standbydb' AS 
         CONNECT IDENTIFIER IS standbydb MAINTAINED AS PHYSICAL;
DGMGRL> ENABLE CONFIGURATION;
DGMGRL> EDIT CONFIGURATION SET PROTECTION MODE AS MAXAVAILABILITY;

3.2 Switchover Test
DGMGRL> SWITCHOVER TO standbydb;

4. Flashback & Guaranteed Restore Points
Enable Flashback Database:
ALTER DATABASE FLASHBACK ON;
Before patching/upgrades:
CREATE RESTORE POINT before_patch GUARANTEE FLASHBACK DATABASE;
Rollback:
FLASHBACK DATABASE TO RESTORE POINT before_patch;

5. Performance: Enterprise Gold Standard
5.1 Memory (Disable AMM Forever)
ALTER SYSTEM SET memory_target=0 SCOPE=SPFILE;
ALTER SYSTEM SET sga_target=8G SCOPE=SPFILE;
ALTER SYSTEM SET pga_aggregate_target=2G SCOPE=SPFILE;

5.2 SGA Breakdown
SELECT component, ROUND(current_size/1024/1024,0) "MB"
FROM v$sga_dynamic_components;

5.3 AWR Baselines
BEGIN
  DBMS_WORKLOAD_REPOSITORY.CREATE_BASELINE(
    start_snap_id => 100, end_snap_id => 110,
    baseline_name => 'MONTHLY_BASELINE');
END;
/

5.4 I/O Calibration
DECLARE
  lat INTEGER; iops INTEGER; mbps INTEGER;
BEGIN
  DBMS_RESOURCE_MANAGER.CALIBRATE_IO(
    num_physical_disks => 8, max_latency => 10,
    max_iops => iops, max_mbps => mbps, actual_latency => lat);
  DBMS_OUTPUT.PUT_LINE('Max IOPS: ' || iops);
END;
/

6. RAC-Specific Checks
Global Cache Health:
SELECT inst_id, event, total_waits
FROM gv$system_event WHERE event LIKE 'gc%';
Interconnect:
SELECT * FROM gv$cluster_interconnects;

7. TDE Encryption
-- Create wallet in ASM
ADMINISTER KEY MANAGEMENT CREATE KEYSTORE '+DATA' IDENTIFIED BY secret;
-- Open & create master key
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY secret;
ADMINISTER KEY MANAGEMENT SET KEY IDENTIFIED BY secret WITH BACKUP;
-- Encrypt tablespace online
ALTER TABLESPACE users ENCRYPTION ONLINE USING 'AES256' ENCRYPT;

8. Health Check Script
Save as /home/oracle/scripts/health_check.sh and cron it daily:

#!/bin/bash
# Enterprise Oracle Health Check | 19c/23c/RAC/ASM
# Covers: OS, DB, ASM, RMAN, Performance, Blocking Sessions
DATE=$(date +"%Y-%m-%d_%H-%M-%S")
LOG_DIR="/u02/health_logs"
LOG_FILE="$LOG_DIR/health_$DATE.log"

mkdir -p "$LOG_DIR"
exec > >(tee -a "$LOG_FILE")
exec 2>&1

GREEN='\033[0;32m' RED='\033[0;31m' YELLOW='\033[1;33m' NC='\033[0m'

print_header() {
    echo "=================================================="
    echo " ORACLE ENTERPRISE HEALTH CHECK - $DATE"
    echo "=================================================="
}

check_critical() {
    if [ $? -ne 0 ]; then
        echo -e "${RED}✗ FAIL: $1${NC}"
        CRITICAL=1
    else
        echo -e "${GREEN}✔ PASS: $1${NC}"
    fi
}

print_header

# [1] OS Health
echo -e "\n${YELLOW}[1] OS STATUS${NC}"
uptime
free -h | head -n 3
df -h /u0 /u01 /u02 /u03 2>/dev/null | head -n 10
check_critical "Disk space OK"

# [2] Oracle 19c/23c Detection & Status
for env_file in /home/oracle/scripts/setEnv*.sh; do
    if [ -f "$env_file" ]; then
        echo -e "\n${YELLOW}[2] $(basename $env_file)${NC}"
        source "$env_file"
        sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 FEEDBACK OFF ECHO OFF
SELECT 'DB: '||name||' - '||open_mode||' - '||log_mode FROM v\$database;
SELECT 'Instance: '||instance_name||' - '||status FROM v\$instance;
SELECT 'PDBS: '||COUNT(*)||' pluggable DBs' FROM v\$pdbs;
SELECT 'Jobs: '||COUNT(*)||' running jobs' FROM dba_scheduler_running_jobs;
EXIT;
EOF
        check_critical "Oracle DB responsive"
    fi
done

# [3] RAC Cluster (if exists)
if command -v crsctl >/dev/null 2>&1; then
    echo -e "\n${YELLOW}[3] RAC CLUSTER${NC}"
    crsctl check crs
    srvctl status database -d * 2>/dev/null | head -n 20
    check_critical "Clusterware OK"
fi

# [4] ASM Status
if command -v asmcmd >/dev/null 2>&1; then
    echo -e "\n${YELLOW}[4] ASM DISKGROUPS${NC}"
    asmcmd lsdg --suppress | head -n 20
    asmcmd lsof | grep -v "TYPE.*ASMP" | head -n 10
    check_critical "ASM healthy"
fi

# [5] FRA & Archivelog
echo -e "\n${YELLOW}[5] RECOVERY AREA${NC}"
sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0
COL used_gb FORMAT 999.0
COL total_gb FORMAT 999.0
SELECT 'FRA: '||name||' Used: '||ROUND(space_used/1024/1024/1024,1)||
       'GB / Limit: '||ROUND(space_limit/1024/1024/1024,1)||'GB ('||
       ROUND(space_used*100/space_limit,1)||'%)' used_gb
FROM v\$recovery_file_dest;
SELECT 'Archivelog: '||log_mode FROM v\$database;
SELECT 'Seq: '||thread#||'.'||sequence#||' Dest: '||dest_id||' Status: '||status
FROM v\$archived_log WHERE completion_time > SYSDATE-1 ORDER BY completion_time;
EXIT;
EOF

# [6] RMAN Backup Status (Last 7 days)
echo -e "\n${YELLOW}[6] RMAN BACKUPS${NC}"
rman target / <<EOF
SET ECHO OFF
LIST BACKUP SUMMARY WHERE completion_time > 'SYSDATE-7';
EXIT;
EOF
check_critical "RMAN accessible"

# [7] Blocking Sessions & Long Runners
echo -e "\n${YELLOW}[7] SESSIONS${NC}"
sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 LINESIZE 200
-- Blockers
SELECT 'BLOCKER: '||s1.sid||'->'||s2.sid||' SQL: '||
       s2.sql_id||' USER: '||s2.username||' WAIT: '||s2.event
FROM v\$lock l1, v\$session s1, v\$lock l2, v\$session s2
WHERE s1.sid = l1.sid AND s2.sid = l2.sid
AND l1.BLOCK = 1 AND l2.request > 0
AND l1.id1 = l2.id1 AND l1.id2 = l2.id2;

-- Top CPU
SELECT 'CPU_HOG: '||sid||' '||username||' '||program||' CPU: '||cpu_time
FROM v\$session WHERE cpu_time > 3600 ORDER BY cpu_time DESC;

EXIT;
EOF

# [8] Performance Alerts
echo -e "\n${YELLOW}[8] PERFORMANCE${NC}"
sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0
-- Top waits (last hour)
SELECT 'WAIT: '||event||' '||total_waits||' waits '||ROUND(time_waited/100,1)||'s'
FROM (SELECT event, total_waits, time_waited FROM v\$system_event
      WHERE time_waited > 0 AND event NOT LIKE '%SQL*Net%'
      ORDER BY time_waited DESC) WHERE ROWNUM <= 5;

-- Invalid objects
SELECT 'INVALID: '||COUNT(*)||' objects' FROM dba_objects WHERE status='INVALID';

-- Tablespace usage
SELECT 'TS: '||tablespace_name||' '||ROUND(used_percent,1)||'% full'
FROM dba_tablespace_usage_metrics WHERE used_percent > 80;

EXIT;
EOF

# [9] Listener & Network
echo -e "\n${YELLOW}[9] LISTENER${NC}"
lsnrctl status | head -n 30

echo -e "\n${GREEN}==================================================${NC}"
echo -e "${GREEN}✓ HEALTH CHECK COMPLETE | Log: $LOG_FILE${NC}"
echo -e "${GREEN}✓ Run time: $(date -d 'now' --date='5 seconds ago' +%H:%M:%S)${NC}"

[ "${CRITICAL:-0}" -eq 1 ] && echo -e "${RED} CRITICAL ISSUES DETECTED${NC}"
exit ${CRITICAL:-0}

Cron: 0 6 * * * /home/oracle/scripts/health_check.sh

9. Data Guard Automation Scripts
dg_setup.sh - Full Broker Config

#!/bin/bash
# Data Guard Broker: Primary → Standby Setup
source /home/oracle/.bash_profile

# On PRIMARY
sqlplus / as sysdba <<EOF
ALTER SYSTEM SET dg_broker_start=TRUE;
ALTER SYSTEM SET log_archive_dest_2='SERVICE=standbydb VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=standbydb';
ALTER SYSTEM SET fal_server=standbydb;
ALTER SYSTEM SET standby_file_management=AUTO;
EOF

# Broker config (run on PRIMARY)
dgmgrl sys/secret@primary <<EOF
CREATE CONFIGURATION 'DGCONFIG' AS PRIMARY DATABASE IS 'primary' CONNECT IDENTIFIER IS primary;
ADD DATABASE 'standby' AS CONNECT IDENTIFIER IS standby MAINTAINED AS PHYSICAL;
EDIT DATABASE 'standby' SET STATE='APPLY-ON';
EDIT CONFIGURATION SET PROTECTION MODE AS MAXAVAILABILITY;
ENABLE CONFIGURATION;
SHOW CONFIGURATION;
EXIT;
EOF

dg_health.sh - Daily Guard Check

#!/bin/bash
dgmgrl -silent sys/secret <<EOF
SHOW CONFIGURATION VERBOSITY=1;
SHOW DATABASE VERBOSITY=1;
EXIT;
EOF | grep -E "(SUCCESS|OK|ERROR|WARNING)"

10. RAC-Specific Monitoring
rac_global_cache.sh - GC Performance

#!/bin/bash
sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 LINESIZE 200
COL inst FORMAT A10
COL event FORMAT A30

-- Global Cache Cr/Current stats (should be <5% of DB time)
SELECT inst_id inst, event, total_waits, time_waited
FROM gv\$system_event 
WHERE event LIKE 'gc%' 
ORDER BY inst_id, time_waited DESC;

-- GCS stats (high numbers = network bottleneck)
SELECT inst_id, SUM(value) blocks
FROM gv\$ges_statistics 
WHERE name IN ('gc cr blocks received','gc current blocks received')
GROUP BY inst_id;

-- Interconnect
SELECT * FROM gv\$cluster_interconnects;

EXIT;
EOF

rac_balance_check.sh - Instance Load Balancing

#!/bin/bash
srvctl status database -d racdb -v
crsctl stat res -t | grep ora.racdb.db
sqlplus -s / as sysdba <<EOF
SELECT inst_id, instance_name, host_name, status, active_state FROM gv\$instance;
SELECT inst_id, COUNT(*) sessions FROM gv\$session GROUP BY inst_id;
EXIT;
EOF

11. Production Cron Schedule
# /etc/cron.d/oracle_monitoring
# Health checks
0 6 * * * oracle /home/oracle/scripts/master_control.sh

# RMAN Incremental Merge (2AM daily)
0 2 * * 1-5 oracle /home/oracle/scripts/rman_incr_merge.sh

# Data Guard health (hourly)
5 * * * * oracle /home/oracle/scripts/dg_health.sh >> /u02/logs/dg_health.log

# RAC cache monitoring (15min)
*/15 * * * * oracle /home/oracle/scripts/rac_global_cache.sh >> /u02/logs/rac_cache.log

# AWR export (midnight)
0 0 * * 1 oracle @$ORACLE_HOME/rdbms/admin/awrrpt.sql

12 Quick Deploy Commands
# Deploy all scripts
$ mkdir -p /home/oracle/scripts /u02/{health_logs,logs}
$ chown -R oracle:oinstall /home/oracle/scripts /u02
$ chmod +x /home/oracle/scripts/*.sh

# Test run
$ su - oracle -c "/home/oracle/scripts/master_control.sh"

# Add to crontab
$ su - oracle -c "crontab /home/oracle/scripts/oracle_cron"

Oracle 19c Production Deployment on Oracle Linux 8

This guide gets you from zero to a rock-solid Oracle Database 19c (19.3) setup on Oracle Linux 8. Perfect for labs, staging, or production (with security notes). We'll cover OS prep, tuning, install, CDB/PDB creation, and everything to make it production-ready.

Quick Planning: What You'll Need
ComponentMinimumRecommended (Prod)
RAM4 GB8–16 GB
Swap2 GB1.5× RAM (if <16GB)
Disk (Software)10 GB20 GB
Disk (Data)20 GBWorkload-dependent
CPU2 cores4+ cores

Pro tip: For production, aim for SSDs and separate disks for data/FRA.

1. Prep Your OS
First, update everything and grab Oracle's required packages:
$ sudo dnf update -y && sudo reboot
$ sudo dnf install -y bc binutils compat-libstdc++-33 elfutils-libelf elfutils-libelf-devel fontconfig-devel glibc glibc-devel ksh libaio libaio-devel libXrender libXrender-devel libX11 libXau libXi libXtst libgcc librdmacm-devel libstdc++ libstdc++-devel libxcb make net-tools  nfs-utils python3 smartmontools sysstat gcc unixODBC libnsl libnsl2

2. Memory & Swap Setup
Check your RAM:
$ sudo free -h
If needed, create swap (e.g., 8GB):
$ sudo fallocate -l 8G /swapfile
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile
$ sudo echo '/swapfile swap swap defaults 0 0' | sudo tee -a /etc/fstab

3. Kernel Tuning
Edit /etc/sysctl.conf and add these Oracle 19c parameters:
$ sudo vi /etc/sysctl.conf
# Oracle 19c Kernel Parameters
fs.file-max = 6815744
kernel.sem = 250 32000 100 128
kernel.shmmni = 4096
kernel.shmall = 1073741824     # ~4GB in pages
kernel.shmmax = 4398046511104  # Match your max SGA
fs.aio-max-nr = 1048576
net.ipv4.ip_local_port_range = 9000 65500
net.core.rmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_default = 262144
net.core.wmem_max = 1048576
wq! --Save file
Apply: $ sudo sysctl -p

4. HugePages for Production
Disable Transparent HugePages (causes latency):
$ sudo grubby --update-kernel=ALL --args="transparent_hugepage=never"
$ sudo reboot
$ sudo cat /sys/kernel/mm/transparent_hugepage/enabled  # Should show "never"

Calculate & set static HugePages:
Estimate SGA (e.g., 6GB = 6144MB)
HugePages = SGA / 2MB = ~3072 pages
Add to $ sudo vi /etc/sysctl.conf: 
vm.nr_hugepages=3072
$ sudo sysctl -p

Why? HugePages eliminate TLB overhead—10-20% perf gain.

5. Oracle User & Directories
$ sudo groupadd -g 54321 oinstall
$ sudo groupadd -g 54322 dba
$ sudo groupadd -g 54323 oper
$ sudo useradd -u 54321 -g oinstall -G dba,oper oracle
$ sudo passwd oracle

$ sudo mkdir -p /u01/app/oracle/product/19.0.0/dbhome_1 /u01/app/oraInventory
$ sudo mkdir -p /u02/oradata /u03/fra
$ sudo chown -R oracle:oinstall /u01 /u02 /u03
$ sudo chmod -R 775 /u01 /u02 /u03

6. Lab Only: Disable Firewall/SELinux
# systemctl stop firewalld && sudo systemctl disable firewalld
# setenforce 0

Production: Open only port 1521: 
# firewall-cmd --permanent --add-port=1521/tcp 
# firewall-cmd --reload

7. Oracle Environment (as oracle user)
$ su - oracle
$ cat > ~/.bash_profile << 'EOF'
export ORACLE_BASE=/u01/app/oracle
export ORACLE_HOME=$ORACLE_BASE/product/19.0.0/dbhome_1
export ORACLE_SID=cdb1
export PATH=$ORACLE_HOME/bin:$PATH
export LD_LIBRARY_PATH=$ORACLE_HOME/lib
EOF
source ~/.bash_profile

8. Install Oracle Software (Silent Mode)
$ cd $ORACLE_HOME
$ unzip LINUX.X64_193000_db_home.zip
$ export CV_ASSUME_DISTID=OEL7.6  # OL8 compatibility trick

$ ./runInstaller -silent -waitforcompletion -responseFile $ORACLE_HOME/install/response/db_install.rsp oracle.install.option=INSTALL_DB_SWONLY ORACLE_HOME=$ORACLE_HOME ORACLE_BASE=$ORACLE_BASE oracle.install.db.InstallEdition=EE DECLINE_SECURITY_UPDATES=true

Run root scripts when prompted:
$ sudo /u01/app/oraInventory/orainstRoot.sh
$ sudo /u01/app/oracle/product/19.0.0/dbhome_1/root.sh

9. Apply Latest RU
Download from My Oracle Support. Then:
$ORACLE_HOME/OPatch/opatch version
$ORACLE_HOME/OPatch/opatch apply -silent
$ORACLE_HOME/OPatch/opatch lspatches

10. Create CDB + PDB
$ dbca -silent -createDatabase \
-templateName General_Purpose.dbc \
-gdbname cdb1 -sid cdb1 -createAsContainerDatabase true \
-numberOfPDBs 1 -pdbName pdb1 \
-characterSet AL32UTF8 \
-totalMemory 4096 -storageType FS \
-datafileDestination "/u02/oradata"

11. Production Essentials
Enable Archivelog:
$ sqlplus / as sysdba
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER DATABASE ARCHIVELOG;
ALTER DATABASE OPEN;
ARCHIVE LOG LIST;

Fast Recovery Area:
ALTER SYSTEM SET db_recovery_file_dest='/u03/fra' SCOPE=BOTH;
ALTER SYSTEM SET db_recovery_file_dest_size=50G SCOPE=BOTH;

12. Auto-Start with systemd
Create /etc/systemd/system/oracle-rdbms.service:
$ vi /etc/systemd/system/oracle-rdbms.service
[Unit]
Description=Oracle Database Service
After=network.target

[Service]
Type=forking
User=oracle
ExecStart=/u01/app/oracle/product/19.0.0/dbhome_1/bin/dbstart $ORACLE_HOME
ExecStop=/u01/app/oracle/product/19.0.0/dbhome_1/bin/dbshut $ORACLE_HOME
Restart=no

[Install]
WantedBy=multi-user.target

wq! --Save file

Enable:
$ sudo systemctl daemon-reload
$ sudo systemctl enable oracle-rdbms

13. Quick Validation
-- DB status
SELECT name, open_mode, log_mode FROM v$database;
-- PDBs
SHOW PDBS;
-- Memory
SHOW PARAMETER sga; SHOW PARAMETER pga;
-- Invalid objects
SELECT owner, object_name, status FROM dba_objects WHERE status='INVALID';
Listener: lsnrctl status

14. Security Hardening
ALTER USER sys IDENTIFIED BY YourStrongPass123!;
ALTER USER system IDENTIFIED BY YourStrongPass123!;

-- Lock sample schemas
ALTER USER hr ACCOUNT LOCK;
-- etc. for sh, oe, pm, ix, sa

15. RMAN Backup Config
rman target /
CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 7 DAYS;
CONFIGURE CONTROLFILE AUTOBACKUP ON;

16. Health Check Commands
WhatCommand
Listenerlsnrctl status
ArchivelogARCHIVE LOG LIST;
FRASELECT * FROM v$recovery_file_dest;
TablespacesSELECT * FROM dba_tablespace_usage_metrics;
Alert Logtail -f $ORACLE_BASE/diag/rdbms/cdb1/cdb1/trace/alert_cdb1.log

17. Common Fixes
ORA-12514 (TNS:listener doesn't know service): ALTER SYSTEM REGISTER;
ORA-00845 (MEMORY_TARGET not supported on this system): Switch to ASMM:
ALTER SYSTEM SET memory_target=0 scope=spfile;
ALTER SYSTEM SET sga_target=4G scope=spfile;
ALTER SYSTEM SET pga_aggregate_target=1G scope=spfile;
SHUTDOWN IMMEDIATE; STARTUP;

Configuring Sendmail on RHEL/CentOS

Sendmail setup using generic placeholders for easy adaptation across environments. All outbound mail relays through your SMTP server while masquerading as the corporate domain.

Prerequisites
  • RHEL 8/9, CentOS 8/9
  • Root or sudo access
  • Network access to <smtp_server> on port 25
  • Replace <smtp_server> and <smtp_client_server> with actual hostnames before deployment
1: Install and Enable Packages
dnf update -y || yum update -y
dnf install -y s-nail sendmail sendmail-cf m4 || yum install -y s-nail sendmail sendmail-cf m4
systemctl enable --now sendmail
systemctl status sendmail

2: Configure sendmail.mc
vi /etc/mail/sendmail.mc
Add these configuration lines (append to end, before final dnl):
define(`SMART_HOST', `<smtp_server>')dnl
define(`RELAY_MAILER_ARGS', `TCP $h 25')dnl
define(`ESMTP_MAILER_ARGS', `TCP $h 25')dnl
FEATURE(`always_add_domain')dnl
FEATURE(`masquerade_envelope')dnl
MASQUERADE_AS(`example.com')dnl
FEATURE(`masquerade_entire_domain')dnl
MASQUERADE_DOMAIN(`<smtp_client_server>')dnl
FEATURE(`accept_unresolvable_domains')dnl
EXPOSED_USER(`root')dnl

3: Generate Configuration Files
cd /etc/mail
cp sendmail.mc sendmail.mc.backup  # Backup original
m4 sendmail.mc > sendmail.cf
newaliases  # Rebuild aliases database
Before running m4, substitute placeholders if needed:
sed -i "s/<smtp_server>/your.actual.smtp.server/g" /etc/mail/sendmail.mc
sed -i "s/<smtp_client_server>/your.actual.client.server/g" /etc/mail/sendmail.mc

4: Security and Firewall Setup
# Firewall (firewalld)

firewall-cmd --permanent --add-service=smtp --add-port=25/tcp
firewall-cmd --reload
# SELinux adjustments (if enforcing)
setsebool -P httpd_can_sendmail 1
setsebool -P sendmail_can_write_config 1
# Restrict to local submissions only
echo "O DaemonOptions=Port=smtp,Addr=127.0.0.1, Name=MTA" >> /etc/mail/sendmail.cf

5: Restart and Verify
systemctl restart sendmail
systemctl status sendmail
ss -tlnp | grep :25  # Verify listening on localhost:25

6: Test Email Delivery
# Basic test
echo "Test message from $(hostname -f) at $(date)" | mail -s "Sendmail Configuration Test" sysadm@
example.com
# Test with full headers
echo -e "Subject: Detailed Test\nFrom: $(hostname) <root@$(hostname -d)>\nTo: sysadm@
example.com\n\nServer: $(uname -a)" | sendmail -v sysadm@example.com
# Monitor logs
tail -f /var/log/maillog

Troubleshooting Common Issues
IssueSymptoms in /var/log/maillogSolution
Relay access deniedrelay access deniedVerify <smtp_server> accepts your IP; test telnet <smtp_server> 25
Hostname resolutionName server timeoutAdd <smtp_client_server> $(hostname) to /etc/mail/local-host-names
Masquerade failureEmails show internal hostnameCheck MASQUERADE_AS matches relay requirements
m4 syntax errorm4: cannot open fileVerify all dnl line endings; restore from backup
Queue buildupmailq shows deferredsendmail -q -v; check smart host connectivity

Production Validation Commands
# Verify masquerading works
echo "test" | mail -s "Masquerade test" external@example.com
# Check queue
mailq | tail
# Test local delivery
echo "Local test" | mail -s "Local" root@localhost
# Comprehensive relay test
telnet <smtp_server> 25 << EOF
EHLO $(hostname)
MAIL FROM: <test@example.com>
RCPT TO: <sysadm@example.com>
DATA
Subject: Telnet Test
.
QUIT
EOF

Installing IBM DB2 Express-C 10.5 on Linux

IBM DB2 Express-C 10.5 is a lightweight, no-cost DB2 edition commonly found in legacy enterprise systems. While EOL, it’s still required for:
  • Supporting older applications
  • Migration source databases
  • Lab and proof-of-concept systems
1. System Prerequisites & Validation
1.1 OS Compatibility
RequirementMinimum
Architecture            x86_64
Kernel            2.6.32+
glibc            2.12+
RAM            2 GB (4 GB recommended)
Disk            4 GB minimum

Verify:
uname -m
uname -r
ldd --version
free -m
df -h

1.2 Disable SELinux (Legacy Requirement)
DB2 10.5 is not SELinux-aware
setenforce 0
vi /etc/selinux/config
SELINUX=permissive
Verify:
getenforce

2. OS User & Group Preparation
2.1 Create Installation & Instance User
sudo useradd -m -G wheel,bin build
sudo passwd build
This user will:
Own the DB2 instance
Run DB2 processes
Manage databases
Verify:
id build

3.2 Required OS Packages
sudo yum install -y \
compat-libstdc++-33 \
compat-libstdc++-296 \
gcc gcc-c++ \
ksh libaio compat-db
Verify:
rpm -qa | grep compat

3. Kernel & Resource Tuning
3.1 Shared Memory & File Limits

Edit:
sudo vi /etc/sysctl.conf
Add:
kernel.shmmax = 1073741824
kernel.shmmin = 1
kernel.shmmni = 4096
kernel.shmseg = 32
kernel.shmall = 1179648
fs.file-max = 65536
Apply:
sudo sysctl -p
Optional but recommended:
sudo reboot

3.2 User Limits
Edit:
sudo vi /etc/security/limits.conf
Add:
build soft nofile 65536
build hard nofile 65536
build soft nproc 2048
build hard nproc 4096
Verify:
su - build
ulimit -a

4. Download & Extract DB2 Express-C
4.1 Download
ssh build@p62
wget https://www6.software.ibm.com/sdfdl/v2/regs2/db2pmopn/db2_v105/expc/v10.5fp1_linuxx64_expc.tar.gz
Verify:
ls -lh v10.5fp1_linuxx64_expc.tar.gz

4.2 Extract
tar -xvzf v10.5fp1_linuxx64_expc.tar.gz
This creates:
server_expc/
 ├── db2_install
 └── response/

5. Install DB2 Software silent Installation
cd expc
sudo ./db2_install \
-b /opt/ibm/db2/V10.5 \
-p server \
-l /tmp/db2_install.log
Options explained:
-b → Base installation directory
-p server → DB2 server components only
-l → Installation log file
Verify:
grep -i error /tmp/db2_install.log
Cleanup:
cd ..
rm -rf expc

6. Create DB2 Instance instance Creation
cd /opt/ibm/db2/V10.5/instance/
sudo ./db2icrt -u build:fenced build -k 50000
What this does:
Creates instance build
Uses fenced user build
Assigns port 50000
Creates /home/build/sqllib
Verify:
ls /home/build/sqllib

7. Configure TCP/IP & Services Set Environment
su - build
cd ~/sqllib
./adm/db2set DB2COMM=TCPIP
Verify:
bin/db2 get dbm cfg | grep TCPIP
8.2 Set Service Port
bin/db2 update dbm cfg using SVCENAME 50000
Restart DB2:
bin/db2stop
./adm/db2start
Verify listener:
netstat -tlnp | grep 50000

8. Create Sample Database
bin/db2sampl
This creates:
Database: SAMPLE
Tables, views, indexes
Test data
Verify:
bin/db2 connect to SAMPLE
bin/db2 "select count(*) from sysibm.sysdummy1"

9. Firewall & Security Hardening
9.1 Open DB2 Port
sudo firewall-cmd --permanent --add-port=50000/tcp
sudo firewall-cmd --reload
Verify:
firewall-cmd --list-ports

9.2 Authentication Configuration
bin/db2 update dbm cfg using AUTHENTICATION SERVER
bin/db2set DB2AUTH=LOCAL
Restart:
bin/db2stop
./adm/db2start

10. JDBC Driver Configuration
JDBC drivers are located at:
/home/build/sqllib/java/db2jcc.jar
/home/build/sqllib/java/db2jcc_license_cu.jar
Add both to application classpath:
export CLASSPATH=$CLASSPATH:/home/build/sqllib/java/*

11. Performance Tuning
11.1 Database Manager Tuning
bin/db2 update dbm cfg using DFT_DEGREE 8
bin/db2 update dbm cfg using SHEAPTHRES 16384
11.2 Instance Parameters
bin/db2 update instance cfg using NUM_INITAGENTS 5
Restart:
bin/db2stop
./adm/db2start
Monitor:
db2pd -db SAMPLE -applications

12. Backup & Recovery Basics offline Backup
mkdir ~/db2backup
bin/db2 backup db SAMPLE to ~/db2backup
Verify:
ls ~/db2backup

13. Verification Checklist
bin/db2level
bin/db2 connect to SAMPLE
bin/db2 "select current timestamp from sysibm.sysdummy1"
db2stop
./adm/db2start
Expected:
DB2 10.5 FP1 displayed
Successful connection
Clean restart

14. Migration & Upgrade Note
DB2 10.5 is End of Life
Recommended target:
IBM Db2 11.5 LTS
Migration tools:
db2move
db2look
IBM Data Server Migration Toolkit
NuoDB / Oracle / PostgreSQL migration utilities

15. Final Thoughts
This installation is best suited for:
  • Legacy app support
  • Data migration staging
  • Test & lab environments
For production systems, upgrade immediately to Db2 11.5 with native TLS, container support, and modern security defaults.