In my previous post, I showed how to call the Oracle Private AI Services Container REST endpoint from PL/SQL to generate vector embeddings over HTTP. This post takes the next step: configuring Oracle AI Database 26ai to connect to the Oracle Private AI Services Container over HTTPS (TLS) for a secure, production-ready deployment.

Compared to an HTTP-only setup, HTTPS requires two additional configuration steps:

  1. A TLS certificate, so the database can validate and trust the service endpoint
  2. An API key, so calls from the database to the container are authenticated

Once created, both artifacts must be transferred from the container host to the database server.

To keep things as easy as possible, we’ll use the simplest HTTPS configuration: a self-signed certificate enabling TLS 1.3 for internal deployments. Please keep in mind: A self-signed certificate is not issued or signed by a Certificate Authority (CA).

You’ll learn how to copy the required certificate and API key, configure Oracle AI Database 26ai accordingly, and validate secure connectivity to the Oracle Private AI Services Container’s endpoint.

The get a quick overview about the topics provided, the posting is divided into the following three section:

Let’s get started.

Accessing the Oracle Private AI Services Container using a REST endpoint

Prerequisite – A Running Private AI Services Container

I’m going to assume you already have the Oracle Private AI Services Container running, and its REST endpoint exposed. Please refer to the Oracle Private AI Services Container User Guide for more information such as download, setup, and installation.

First, let’s verify the container’s status on its host with the following podman ps command.

podman ps

CONTAINER ID IMAGE                                                        COMMAND CREATED       STATUS        PORTS                  NAMES
7b148f11c142 container-registry.oracle.com/database/private-ai:25.1.3.0.0         9 seconds ago Up 10 seconds 0.0.0.0:8443->8443/tcp privateai

You’ll see that the container was started with HTTP/SSL enabled and is running on port 8443.

Step 1 – Copying the container certificate to the database server

After running the container’s setup scripts a certificate file, for example,  cert.pem  appears under the container host user’s secrets directory (for example, /home/opc/secrets).

You will need to copy the certificate to the database server (via scp or sftp, etc.) and place it into a temporary directory (for example, /u01/app/oracle/temp).

Next, you need to verify the container’s fully‑qualified hostname and confirm that it matches the certificate’s Common Name (CN). You can do so with the following shell commands:

export HOST=$(hostname -f)
echo $HOST

The response looks like this:

your-fully-qualified-hostname

Step 2 – Test the HTTPS endpoint from the database server

To test you can reach the Private AI Services Container endpoint from the database server, you can run the following command:

curl -i --cacert /u01/app/oracle/temp/cert.pem https://your-fully-qualified-hostname:8443/health

The expected response should look something like this:

HTTP/1.1 200 OK
date: Thu, 12 Feb 2026 14:07:00 GMT
x-ratelimit-limit-requests: 60
x-ratelimit-remaining-requests: 59
x-ratelimit-reset-requests: 1
x-server-id: b6d4c06e-490c-4988-9012-6fd3f959ce51
content-length: 0

If you get 200 OK, TLS works and the container is reachable.

Step 3 – Create an Oracle wallet and trust the container certificate

For this step, please consult to the Oracle Security Guide.

The database uses an Oracle Wallet as its trust store for outbound HTTPS.

a. Set your Oracle environment:

. oraenv

ORACLE_SID = [oracle] ? your_sid

The response looks like this:

The Oracle base has been set to /u01/app/oracle

b. Create a wallet directory (example path – adjust to your environment):

mkdir -p $ORACLE_HOME/admin/db_unique_name/wallet_privateai
chown oracle:oinstall $ORACLE_HOME/admin/db_unique_name/wallet_privateai
chmod 700 $ORACLE_HOME/admin/db_unique_name/wallet_privateai

c. Create the wallet with the command-line tool orapki:

orapki wallet create -wallet $ORACLE_HOME/admin/db_unique_name/wallet_privateai -pwd wallet_password

d. Add the container certificate as a trusted cert:

orapki wallet add -wallet $ORACLE_HOME/admin/db_unique_name/wallet_privateai \
  -trusted_cert -cert $ORACLE_HOME/temp/cert.pem -pwd wallet_password

e. Verify it was added:

orapki wallet display -wallet $ORACLE_HOME/admin/db_unique_name/wallet_privateai -pwd wallet_password

Step 4 – Allow the database user to connect to the container (Network ACL)

The Oracle Database restricts outbound network calls. A DBA must grant a network ACL (ACE) allowing access to the container host and port.

The PL/SQL block below grants Access-Control Entry (ACE) with the HTTP privilege to the user vectordb on “host”, which is your-fully-qualified-hostname (port 8443 only). Alternatively, you could grant the CONNECT privilege. It provides additional capabilities that we don’t need for this example.

For more information on granting ACE privileges, see the Oracle AI Vector Search User’s Guide.

The same section also explains how to configure a proxy server (if applicable).

BEGIN
  DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
    host => 'your-fully-qualified-hostname',
    lower_port => 8443,
    upper_port => 8443,
    ace  => xs$ace_type(
             privilege_list => xs$name_list('http'),
             principal_name => 'vectordb',
             principal_type => xs_acl.ptype_db));
END;
/

This procedure appends the Access-Control Entry (ACE) to the Access Control List (ACL) of the container host. The ACL controls access to the given host from the database and the ACE specifies the privileges granted to or denied from the specified principal.

Step 5 – Allow the schema to use the wallet (Wallet ACL)

Even with the wallet created, the user must be allowed to use it.
Run the following PL/SQL block as SYSDBA to grant access to the vectordb user:

BEGIN
  DBMS_NETWORK_ACL_ADMIN.APPEND_WALLET_ACE(
    wallet_path => 'file:$ORACLE_HOME/admin/db_unique_name/wallet_privateai',
    ace => xs$ace_type(
             privilege_list => xs$name_list('use_client_certificates', 'use_passwords'),
             principal_name => 'vectordb',
             principal_type => xs_acl.ptype_db));
END;
/

Verify the ACL entry

The database view USER_HOST_ACES shows the ACEs that have been granted to the current schema. You can run the query below to verify that the ACE was granted successfully.

SELECT host, lower_port, upper_port, privilege, status
FROM user_host_aces;

The expected response looks like this:

HOST                          LOWER_PORT UPPER_PORT PRIVILEGE STATUS
----------------------------- ---------- ---------- --------- -------
your-fully-qualified-hostname 8443       8443       HTTP      GRANTED

If the row shows host = ’your-fully-qualified-hostname’, privilege = ‘http’, lower_port = ‘8443’, upper_port= ‘8443’ and status = ‘GRANTED”, the ACE entry is correctly in place.

The database user vectordb can now issue HTTPS requests to https://your-fully-qualified-hostname:8443/

A single misconfiguration is all it takes to break the connection: a typo in the host name, an incorrect port, or a missing ACL will cause the call to the container’s REST endpoint (which we’ll cover in the next step) to fail with ORA‑29273, “HTTP request failed”.

To obtain a detailed error message and identify a missing or incorrect ACL, query the UTL_HTTP.GET_DETAILED_SQLERRM function:

SELECT UTL_HTTP.GET_DETAILED_SQLERRM;

GET_DETAILED_SQLERRM
--------------------------------------------------------------------------------
ORA-24247: network access denied by access control list (ACL)

Also verify firewall/routing if networking is still failing.

Step 6 – Get the API key from the container host

On the container host, locate the file named api-key.
Copy its content. You’ll store it in the database as a credential in the next step.

Step 7 – Create a DBMS_VECTOR credential containing the API key

Connect as the user that will call embeddings and ensure it has permission to create credentials. Ensure it has the create credential privilege.

Drop the old credential, for example, if you are rotating API keys or switching setups.

BEGIN
  DBMS_VECTOR.DROP_CREDENTIAL('PRIVATEAI_CRED');
EXCEPTION
  WHEN OTHERS THEN NULL;
END;
/

Create the new credential. In PL/SQL, API key goes into the access_token.

DECLARE
  jo json_object_t;
BEGIN
  jo := json_object_t();
  jo.put('access_token', 'your_api_key_from_container_host');
  DBMS_VECTOR.CREATE_CREDENTIAL(
    credential_name => 'PRIVATEAI_CRED',
    params          => json(jo.to_string));
END;
/

Call the Container’s Embedding Endpoint from PL/SQL

We are now ready to start generating vectors.

Step 1 – Set the wallet for outbound HTTPS (UTL_HTTP)

You need to set the wallet in the same session before calling the endpoint.

EXEC UTL_HTTP.SET_WALLET('file:/u01/app/oracle/wallet_privateai', 'wallet_password');

Step 2 – Generate an embedding

Let’s run the following PL/SQL to invoke the Private AI Services Container’s REST API, generate an embedding from a plain-text CLOB “hello”, and output the resulting vector.

SET SERVEROUTPUT ON

DECLARE
input clob;
v vector;
BEGIN
  input := 'hello';
   v := DBMS_VECTOR.UTL_TO_EMBEDDING(
    input,
    json('{"provider": "privateai",
    "url": "https://your-fully-qualified-hostname:8443/v1/embeddings",
    "credential": "PRIVATEAI_CRED",
    "model": "all-MiniLM-L12-v2" }'));
   DBMS_OUTPUT.PUT_LINE(vector_serialize(v));
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE (SQLERRM);
    DBMS_OUTPUT.PUT_LINE (SQLCODE);
END;
/

In the all-minilm-l12-v2 model, each embedding is a 384‑element vector; therefore, only a subset of its dimensions is displayed for readability.

[-7.49069378E-002,-1.44330524E-002,4.86498736E-002,-2.71381401E-002,-4.30881716E
-002,-1.47763431E-001,6.88331053E-002,-1.37038641E-002,-5.35686985E-002,2.697533
93E-002,-6.28336193E-003,-3.98834497E-002,7.65678007E-003,-3.78089584E-002,-1.17
557691E-002,-3.46409418E-002,1.29357159E-001,-2.52777934E-002,-1.52099188E-002,7
.30306434E-004,-8.06887969E-002,2.69378684E-002,-9.87357348E-002,-3.4107659E-002
,-2.70293821E-002,-7.32003525E-002,5.08588664E-002,-1.72562916E-002,7.28218406E-
...
98184E-003,8.3617419E-002,3.61523218E-002,-2.27608532E-002,1.09307049E-002,-4.64
579426E-002,-2.51197256E-002,3.10343243E-002,1.40036587E-002,2.80777384E-002,-7.
75460526E-003,-3.13466117E-002,5.54158725E-002]

Call the Container’s Embedding Endpoint from SQL

Step 1 – Set the wallet for outbound HTTPS (UTL_HTTP)

Set the wallet in the same session before calling the endpoint.

EXEC UTL_HTTP.SET_WALLET('file:/u01/app/oracle/wallet_privateai', 'wallet_password');

Step 2 – Call embeddings from SQL

Define the parameters for the REST endpoint with the following PL/SQL block.

VAR params CLOB;

BEGIN
  :params := '{
    "provider": "privateai",
    "credential_name": "PRIVATEAI_CRED",
    "url": "https://your-fully-qualified-hostname:8443/v1/embeddings",
    "model": "multilingual-e5-large"
  }';
END;
/

Let’s create an embedding for the string ”hello” using the SQL statement below.

SELECT DBMS_VECTOR.UTL_TO_EMBEDDING('hello', json(:params)) AS embedding;

In the multilingual-e5-large model, each embedding is a 1024‑element vector; therefore, only a subset of its dimensions is displayed for readability. The model supports about 100 languages.

[2.22402979E-002,-4.5670867E-003,-1.39809772E-002,-5.86821362E-002,1.36979893E-0
02,-3.59046906E-002,-1.66482385E-002,3.06356922E-002,4.58771065E-002,-3.72102596
E-002,2.79148389E-002,1.4809153E-002,-4.95531522E-002,-4.62263748E-002,-4.963218
79E-002,-1.54762566E-002,-1.43705984E-003,2.41220295E-002,3.64369452E-002,-1.793
17091E-002,-3.59369488E-003,-3.41240652E-002,-1.58616491E-002,-6.0151428E-002,-1
.04163783E-002,-1.67176556E-002,-3.02540716E-002,-2.52844356E-002,2.93205958E-00
…
,5.84239792E-003,1.14159677E-002,-3.02890819E-002,5.66903427E-002]579426E-002,-2
.51197256E-002,3.10343243E-002,1.40036587E-002,2.80777384E-002,-7.75460526E-003,
-3.13466117E-002,5.54158725E-002]

Summary

In this blog you learned how to securely connect Oracle AI Database 26ai to the Oracle Private AI Services Container over HTTPS (TLS) instead of HTTP by invoking the container’s /v1/embeddings endpoint using DBMS_VECTOR.UTL_TO_EMBEDDING from PL/SQL and SQL. You also learned what to expect at runtime (including the first-call model load delay) and how to troubleshoot common connectivity issues such as missing ACLs (for example ORA24247/ORA29273). For more information on using the Private AI Services Container, check out the documentation.

Resources