Od
Databases AWS

Oracle Database 21c Enterprise Edition on AWS User Guide

| Product: Oracle Database 21c Enterprise Edition on AWS

Overview

This image runs Oracle Database 21c Enterprise Edition, installed from upstream Oracle media. Oracle Database is the only workload on the image, so the platform stays lean, predictable and easy to reason about. The image ships the 21.3.0.0.0 base release.

Oracle Database 21c desupports the traditional non container architecture, so the starter database is a multitenant container database (CDB) named ORCL with one ready to use pluggable database (PDB) named ORCLPDB. Applications connect to the ORCLPDB service; the ORCL container root is used for administration. Enterprise Edition carries the full multitenant option, supporting up to 252 pluggable databases in a single container, so you can create many more PDBs in this container as your estate grows.

The image ships with no usable database credentials. On the first boot of your instance a one shot service, oracle-db-21c-firstboot.service, runs before the database is reachable. With no listener running, it sets a unique random 24 character password on the SYS and SYSTEM accounts and on PDBADMIN, the administrator of ORCLPDB, and re-keys every other password account (such as DBSNMP and the sample schemas) with a random value and leaves it locked and expired. It then starts the listener on 127.0.0.1 only, proves that each new password works and that the historic and default passwords are refused, and checks that no plaintext password reached the audit trail or the trace files. Only then does it write the passwords to /root/oracle-db-credentials.txt, a file that only the root user can read, followed by the ready marker /var/lib/cloudimg/oracle-db-21c-firstboot.done. The oracle-db.service unit starts the database only after that marker exists.

The Oracle binaries, the datafiles, the redo logs and the archive area live on a dedicated storage volume mounted at /opt/oracle. Keeping the database tier on its own volume means storage can be grown, snapshotted and backed up independently of the operating system disk. The Oracle listener runs on port 1521 bound to the loopback address 127.0.0.1 only, and the default security group opens port 22 only, so the database is not reachable from the network until you decide to make it so. SQL Developer and JDBC clients on your workstation connect through an SSH tunnel; opening port 1521 for direct connections is a deliberate step, described in step 9, that requires network encryption.

This is a headless image. Oracle Database has no web interface in this listing; you administer it over SSH with the sqlplus command line client, and you can connect graphical tools such as Oracle SQL Developer through an SSH tunnel to port 1521.

Enterprise Edition is the full-featured Oracle Database edition for mission-critical and large-scale workloads. It includes the Oracle option set such as Partitioning, Advanced Compression, Advanced Security, Data Guard, Real Application Testing, and the Diagnostics and Tuning Packs, together with the full multitenant option. The cost effective Standard Edition 2 variant on this listing, licensed for servers with a maximum of two sockets (on AWS, instances of up to 8 vCPUs), is available where those option packs are not required.

Prerequisites

Before you deploy this image you need:

  • An Amazon Web Services account where you can launch EC2 instances
  • IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
  • An EC2 key pair in the target Region for SSH access to the instance
  • A VPC and subnet in the target Region, with a security group allowing inbound port 22 from your management network. Port 1521 does not need to be open: the listener is bound to 127.0.0.1 and remote tools reach it through an SSH tunnel
  • The AWS CLI (version 2) installed locally if you plan to deploy from the command line

Recommended instance type: m5.large (2 vCPU, 8 GiB RAM) or larger. The starter database is sized for m5.large. For production workloads choose m5.xlarge or larger and raise the database memory as described in step 11. Enterprise Edition has no socket cap, so scale the instance to your workload; choose more vCPU and RAM for memory intensive or high concurrency production databases.

Step 1: Launch the Instance from the AWS Marketplace

Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images choose AWS Marketplace AMIs and search for Oracle Database. Select the cloudimg listing and choose Select, then Continue on the subscription summary.

Pick an instance type of m5.large or larger. Choose your EC2 key pair under Key pair (login). Under Network settings select your VPC and subnet, and either create or select a security group that allows inbound port 22 from your management network only. The default security group of this listing opens port 22 only; port 1521 does not need to be open, because the listener is bound to 127.0.0.1. Leave the root volume at the default size or larger; the Oracle data volume is attached automatically from the image.

Select Launch instance. First boot initialisation, which sets and then proves the per instance passwords before the database is allowed to start, takes several minutes after the instance state becomes Running and the status checks pass, a few minutes longer than a plain database start.

Step 2: Launch the Instance from the AWS CLI

The following block launches an instance from the cloudimg Oracle Database Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens inbound port 22 from your management network. Port 1521 stays closed.

aws ec2 run-instances \
  --image-id <ami-id> \
  --instance-type m5.large \
  --key-name <key-name> \
  --subnet-id <subnet-id> \
  --security-group-ids <security-group-id> \
  --metadata-options HttpTokens=required \
  --block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":30,"VolumeType":"gp3"}}]' \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=oracle-db-21c-ee-01}]'

The command prints a JSON document on success. Note the instance ID, then retrieve its public address once it is running with aws ec2 describe-instances --instance-ids <instance-id> --query "Reservations[].Instances[].PublicIpAddress" --output text.

Step 3: Connect over SSH

Connect over SSH with the key pair you selected and the public IP address from step 2. The SSH login user depends on the operating system of the AMI variant you launched:

AMI variant SSH login user
Oracle Database 21c EE on Oracle Linux 8 ec2-user
ssh <login-user>@<public-ip>

Wait until the instance has passed both EC2 status checks before connecting. SSH can become available before first boot has finished, so confirm that first boot has completed. The ready marker exists only after every password has been set and proven:

sudo test -f /var/lib/cloudimg/oracle-db-21c-firstboot.done && echo "first boot complete"

If the command prints nothing, first boot is still running; follow its progress with sudo journalctl -u oracle-db-21c-firstboot.service -b -f, and see If first boot fails in step 4 if it does not finish.

Step 4: Retrieve the Generated Credentials

The first boot service generates fresh SYS, SYSTEM and PDBADMIN passwords for this instance and writes them, with the connection details, to /root/oracle-db-credentials.txt. The file is readable only by the root user. Display it from your SSH session:

sudo cat /root/oracle-db-credentials.txt

The file looks like this, with unique passwords on your instance:

# Oracle Database 21c Enterprise Edition - per-instance credentials (cloudimg)
# Generated Sun Oct 18 11:12:04 UTC 2026 on i-0123456789abcdef0. Root-only (0600). Unique to this instance.

SYS_PASSWORD=<your generated SYS password>
SYSTEM_PASSWORD=<your generated SYSTEM password>
PDBADMIN_PASSWORD=<your generated PDBADMIN password>

ORACLE_SID=ORCL
PDB_SERVICE=ORCLPDB
LISTENER=127.0.0.1:1521 (localhost only - use an SSH tunnel, or see the guide to open it deliberately with encryption)

Every other database account is locked and expired with a random password.
Connect: sudo su - oracle ; . ~/setEnv.sh ; sqlplus /nolog ; then CONNECT system@//localhost:1521/ORCLPDB

No shared or default database passwords ship in the image. Use the generated SYSTEM password for application and administrative connections, the SYS password for SYSDBA operations, and the PDBADMIN password to administer the ORCLPDB pluggable database. ORACLE_SID=ORCL is the container root and PDB_SERVICE=ORCLPDB is the service your applications connect to.

The file uses KEY=value lines. Images released before October 2026 wrote KEY= value, with a space after the equals sign. To read a single password into a shell variable in a way that handles both forms:

SYSPWD=$(sudo awk -F'= *' '/^SYSTEM_PASSWORD=/{print $2}' /root/oracle-db-credentials.txt)
test -n "$SYSPWD" && echo "SYSTEM password read (${#SYSPWD} characters)"

Every other account is locked

Only SYS, SYSTEM and PDBADMIN can log in. Every other password account in the container and the pluggable database, including DBSNMP and the sample schemas, was given a random password that nobody knows and is locked and expired. To use one of these accounts, set your own password and unlock it as SYSDBA, in the container that owns the account:

ALTER USER <name> IDENTIFIED BY "<new-strong-password>" ACCOUNT UNLOCK;

If first boot fails

First boot fails closed. If it cannot complete every step, it stops the database and the listener on purpose, writes no credentials file, and leaves /root/oracle-db-FIRSTBOOT-FAILED.txt explaining what happened. Read the notice and the service journal, then reboot once to retry; first boot runs again on every boot until it succeeds:

sudo cat /root/oracle-db-FIRSTBOOT-FAILED.txt
sudo journalctl -u oracle-db-21c-firstboot.service -b
sudo reboot

If it fails again, contact cloudimg support with the journal output.

Run the security self-test

The image includes a self-test that re-proves the security state of the instance: each password in the credentials file works and the historic and default passwords are refused, every other account is locked, the listener is bound to 127.0.0.1 only, and no listener started before the passwords were set:

sudo /usr/local/sbin/cloudimg-oracle-selftest

Each check prints a PASS line and the run ends with SELFTEST_OK. Abridged sample output:

PASS: ready marker present
PASS: no first-boot error notice
PASS: /root/oracle-db-credentials.txt is 0600 root:root
PASS: SYS@ORCL accepts its per-instance password
PASS: SYSTEM@ORCL accepts its per-instance password
PASS: PDBADMIN@ORCLPDB refuses a historic/default password
PASS: PDBADMIN@ORCLPDB accepts its per-instance password
PASS: every other password account is locked
PASS: listener.ora binds 127.0.0.1 only
PASS: no database socket on a non-loopback address
PASS: oracle-db.service gated on the ready marker
PASS: memory fits m5.large: sga_target 2304M, pga_aggregate_target 768M
...
SELFTEST_OK

The self-test checks the instance as delivered. After you rotate a password, open port 1521 or raise the database memory as described in this guide, the matching checks report FAIL by design.

Step 5: Confirm the Database Service and the Listener

Oracle Database starts automatically on boot through the oracle-db.service systemd unit, which runs Oracle's dbstart to open the database and start the listener. Confirm the unit is enabled for automatic start at boot:

systemctl is-enabled oracle-db.service

The command prints enabled. A companion one shot unit, oracle-db-21c-firstboot.service, sets the per instance credentials on the first boot, and oracle-db.service does not start until it has finished and written its ready marker; confirm it is enabled too:

systemctl is-enabled oracle-db-21c-firstboot.service

Confirm the Oracle listener is accepting connections. It binds to the loopback address 127.0.0.1 on port 1521 only, so it is reachable from the instance itself and, through an SSH tunnel, from SQL Developer and JDBC clients on your workstation:

ss -tln | grep ':1521 '

You should see a listening socket on 127.0.0.1:1521, and no other address on port 1521. The screenshot below shows the full lsnrctl status output, with the listening endpoint on port 1521 and the ORCL container and orclpdb pluggable database services registered and ready.

lsnrctl status showing the Oracle listener on port 1521 with the ORCL and ORCLPDB services ready

Step 6: Confirm the Edition and Version

The database runs as the oracle operating system user, whose login environment sets ORACLE_HOME, ORACLE_SID and the library path. Connect to the container root with operating system authentication and query the version views. The following block reports the product banner, which names the edition, and the instance name, full version and open status:

sudo su - oracle -c 'sqlplus -S -L / as sysdba' <<'SQL'
SET PAGESIZE 50 LINESIZE 120 FEEDBACK OFF
SELECT banner FROM v$version WHERE banner LIKE 'Oracle%';
SELECT instance_name, version_full, status FROM v$instance;
EXIT;
SQL

The banner reads Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production, and the instance ORCL reports version 21.3.0.0.0 with status OPEN. The screenshot below shows the client version from sqlplus -V together with this banner and instance query.

SQL*Plus version output and the Oracle Database 21c Enterprise Edition banner with the instance open

Step 7: The Container Database and the Pluggable Database

Oracle Database 21c uses the multitenant architecture. The container database ORCL holds one pluggable database, ORCLPDB, which is where your application schemas and data live. Confirm the pluggable database is open in read write mode:

sudo su - oracle -c 'sqlplus -S -L / as sysdba' <<'SQL'
SET PAGESIZE 50 LINESIZE 120 FEEDBACK OFF
COLUMN name FORMAT a12
COLUMN open_mode FORMAT a12
SELECT name, open_mode FROM v$pdbs WHERE name = 'ORCLPDB';
SELECT sysdate AS server_time FROM dual;
EXIT;
SQL

ORCLPDB reports READ WRITE. The pluggable database is configured with saved state, so it opens automatically whenever the container database starts. With the full multitenant option, Enterprise Edition lets you add more pluggable databases in the same container; clone ORCLPDB or create new PDBs with CREATE PLUGGABLE DATABASE as your estate grows. The screenshot below shows a session that switches into the ORCLPDB container, confirms it is open read write and reads the server time.

A SQL*Plus session switching into the ORCLPDB pluggable database, confirming it is open read write, and reading the server time

Step 8: Connect with SQL*Plus

To run application workloads, connect to the ORCLPDB pluggable database service as the SYSTEM user with the generated password. Switch to the oracle user and source the environment first, then open SQL*Plus. Replace <SYSTEM_PASSWORD> with the value from /root/oracle-db-credentials.txt:

sudo su - oracle
. ~/setEnv.sh
sqlplus system/<SYSTEM_PASSWORD>@localhost:1521/ORCLPDB

Inside SQL*Plus you can create application schemas, tables and data in the pluggable database. The following statements, run at the SQL> prompt, create a table, insert a row and read it back:

CREATE TABLE products (
  id    NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  name  VARCHAR2(100),
  price NUMBER(10,2)
);

INSERT INTO products (name, price) VALUES ('Mechanical Keyboard', 89.00);
COMMIT;

SELECT name, price FROM products;

Enterprise Edition also enables the Partitioning option, so you can range, list or hash partition large tables for manageability and performance. Type EXIT to leave SQL*Plus. To connect to the container root for administration instead, use operating system authentication with sqlplus / as sysdba, or connect over the network as SYS with sqlplus sys/<SYS_PASSWORD>@localhost:1521/ORCL as sysdba. To administer the pluggable database as its own administrator, connect as PDBADMIN with sqlplus pdbadmin/<PDBADMIN_PASSWORD>@localhost:1521/ORCLPDB.

Step 9: Connect Remotely with SQL Developer or JDBC

The listener is bound to 127.0.0.1, and the default security group opens port 22 only, so the database is not reachable from the network. The recommended way to connect SQL Developer, a JDBC driver or any Oracle client on your workstation is an SSH tunnel, which carries the Oracle traffic inside your existing SSH connection and needs no change to the instance or the security group.

Connect through an SSH tunnel

On your workstation, open a tunnel that forwards local port 1521 to the listener on the instance, and leave it running while you work:

ssh -i <your-key.pem> -N -L 1521:127.0.0.1:1521 ec2-user@<public-ip>

While the tunnel is open, localhost:1521 on your workstation reaches the database. Use the following connection details, with the password from the credentials file:

Host:            localhost (through the SSH tunnel)
Port:            1521
Service name:    ORCLPDB
Username:        SYSTEM
Password:        <your generated SYSTEM password>

JDBC URL:        jdbc:oracle:thin:@//localhost:1521/ORCLPDB

In SQL Developer, create a new connection, set the Connection Type to Basic, enter localhost, port 1521 and the ORCLPDB service name, supply the SYSTEM username and generated password, and select Test then Connect. For administrative access to the container root, use the ORCL service name and connect as SYS with the SYSDBA role.

Opening port 1521 deliberately

If your applications must connect directly rather than through a tunnel, open the listener deliberately, in three steps, and only to your own network. Run these commands yourself; none of them is needed for the SSH tunnel.

1. Require Oracle native network encryption and integrity. As the oracle user, append the following to $ORACLE_HOME/network/admin/sqlnet.ora:

sudo su - oracle
. ~/setEnv.sh
cat >> $ORACLE_HOME/network/admin/sqlnet.ora <<'EOF'
SQLNET.ENCRYPTION_SERVER = required
SQLNET.ENCRYPTION_TYPES_SERVER = (AES256)
SQLNET.CRYPTO_CHECKSUM_SERVER = required
SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER = (SHA256)
EOF

Alternatively, configure TCPS (TLS) with an Oracle wallet instead; see "Configuring Transport Layer Security Authentication" in the Oracle Database 21c Security Guide at https://docs.oracle.com/en/database/oracle/oracle-database/21/dbseg/configuring-transport-layer-security-authentication.html.

2. Bind the listener to all interfaces. In $ORACLE_HOME/network/admin/listener.ora (/opt/oracle/product/21.0.0/dbhome_1/network/admin/listener.ora), change (HOST = 127.0.0.1) to (HOST = 0.0.0.0), then restart the listener as the oracle user. The database and the ORCLPDB service register with the restarted listener within a minute:

sudo su - oracle
. ~/setEnv.sh
sed -i 's/(HOST = 127.0.0.1)/(HOST = 0.0.0.0)/' $ORACLE_HOME/network/admin/listener.ora
lsnrctl stop
lsnrctl start

3. Allow TCP 1521 from your own network only. Add a security group rule for your management or application CIDR. Never use 0.0.0.0/0:

aws ec2 authorize-security-group-ingress --group-id <security-group-id> --protocol tcp --port 1521 --cidr <your-mgmt-cidr>

Clients then connect to <public-ip>:1521/ORCLPDB (or the private IP from inside the VPC), or ORCL for the container root, and must also use encryption. The JDBC thin driver, and therefore SQL Developer, negotiates it automatically when the server requires it; other Oracle clients do the same with their default sqlnet.ora settings.

Instances launched from earlier images

On instances launched from images released before October 2026, the listener binds 0.0.0.0 and the old default security group opened port 1521 to the internet. To bring such an instance in line with the current image, remove that security group rule, then set the listener back to 127.0.0.1 in the same listener.ora file and restart it:

aws ec2 revoke-security-group-ingress --group-id <security-group-id> --protocol tcp --port 1521 --cidr 0.0.0.0/0

sudo su - oracle
. ~/setEnv.sh
sed -i 's/(HOST = 0.0.0.0)/(HOST = 127.0.0.1)/' $ORACLE_HOME/network/admin/listener.ora
lsnrctl stop
lsnrctl start

Check that the HOST entry in listener.ora now reads 127.0.0.1. On those images PDBADMIN also kept its build time password, so rotate it. As the oracle user, connect with sqlplus / as sysdba and run:

ALTER SESSION SET CONTAINER=ORCLPDB;
ALTER USER PDBADMIN IDENTIFIED BY "<new-strong-password>";

Then connect through the SSH tunnel described above. If you need direct access instead, follow Opening port 1521 deliberately.

Step 10: The Oracle Data Volume

The Oracle binaries, the datafiles, the redo logs and the archive area are stored under /opt/oracle, which is a dedicated EBS volume separate from the operating system disk. Confirm the mount:

findmnt /opt/oracle

The output shows /opt/oracle is its own xfs filesystem on a separate device. Check the available space at any time with:

df -h /opt/oracle

Because the database tier is on its own volume you can take an Amazon EBS snapshot of it on its own schedule, and you can grow it independently of the root volume.

Step 11: Managing the Database Service

Oracle Database is managed through systemd as the oracle-db.service unit, which starts the database and the listener automatically on boot, as confirmed in step 5. Check the service status:

systemctl status oracle-db.service --no-pager

Stop, start and restart the service when needed. Stopping the service runs Oracle's dbshut to close the database cleanly, and starting it runs dbstart:

sudo systemctl stop oracle-db.service
sudo systemctl start oracle-db.service
sudo systemctl restart oracle-db.service

Database memory and instance size

The starter database is sized for the recommended m5.large (8 GiB): it uses automatic shared memory management with 3072 MB in total, which gives an sga_target of about 2.3 GiB and a pga_aggregate_target of about 768 MiB, leaving room for the operating system. On m5.xlarge or a larger instance for production, raise the database memory as SYSDBA in the container root, for example:

ALTER SYSTEM SET sga_max_size=6G SCOPE=SPFILE;
ALTER SYSTEM SET sga_target=6G SCOPE=SPFILE;
ALTER SYSTEM SET pga_aggregate_target=2G SCOPE=BOTH;

Then restart the database so the new SGA size takes effect with sudo systemctl restart oracle-db.service. Choose values that leave at least 2 GiB of the instance memory for the operating system.

Logs

The Oracle alert log and listener log live under /opt/oracle/diag. Review the alert log first when diagnosing a startup or runtime problem; locate it with:

sudo su - oracle -c 'find /opt/oracle/diag -name alert_ORCL.log'

Step 12: Backups

Oracle Database includes Recovery Manager (RMAN) for consistent, online backups. Run RMAN as the oracle user against the local instance to take a full backup of the container database and its pluggable databases:

sudo su - oracle
. ~/setEnv.sh
rman target / <<'RMAN'
BACKUP DATABASE PLUS ARCHIVELOG;
RMAN

For logical, schema level exports use Oracle Data Pump against the pluggable database:

expdp system/<SYSTEM_PASSWORD>@localhost:1521/ORCLPDB \
  schemas=APPUSER directory=DATA_PUMP_DIR dumpfile=appuser.dmp

Because /opt/oracle is a dedicated EBS volume, you can also take an EBS snapshot of the volume itself for a point in time copy of the entire database tier. For a crash consistent snapshot, place the database in backup mode or shut it down cleanly first.

Support

cloudimg provides 24/7/365 expert technical support for this image. Guaranteed response within 24 hours, one hour average for critical issues. Contact support@cloudimg.co.uk.

For general Oracle Database administration questions consult the official Oracle Database documentation at https://docs.oracle.com/en/database/oracle/oracle-database/21/.