SAP ABAP Platform Trial 2023 — Self-Hosted Setup Guide¶
This document describes how to run the SAP ABAP Platform Trial 2023 Docker container on a Linux server (e.g. Hetzner Cloud), configure it for ADT access, connect it to SAP BTP via Cloud Connector, and wire up the integration test suite and GitHub Actions CI.
Security note: This guide intentionally omits the server IP/hostname. Never commit connection URLs, credentials, or license keys to the repository.
Architecture¶
Internet
│
│ HTTPS :443 HTTPS :8443
▼ ▼
┌─────────────────────────────────────────────────────┐
│ Linux host (Hetzner Cloud) │
│ │
│ nginx (reverse proxy + TLS termination) │
│ ├── :443 → localhost:50000 (ABAP ICM HTTP) │
│ └── :8443 → 172.17.0.2:8443 (CC admin, SSL pass) │
│ │
│ Docker container "a4h" (172.17.0.2) │
│ ├── SAP ABAP Platform Trial 2023 │
│ │ └── ICM listening on :50000 (HTTP) │
│ └── SAP Cloud Connector 2.18 │
│ └── Tomcat listening on :8443 (HTTPS) │
│ └── outbound tunnel → BTP Connectivity │
└─────────────────────────────────────────────────────┘
│
│ Outbound HTTPS (tunnel to BTP)
▼
┌──────────────────────────────┐
│ SAP BTP (us10) │
│ ├── Connectivity Service │
│ ├── Destination Service │
│ └── Subaccount "dev" │
└──────────────────────────────┘
Traffic flows:
| Use case | Path |
|---|---|
| ADT / integration tests | https://<host> → nginx:443 → ABAP:50000 |
| CC admin panel | https://<host>:8443 → nginx:8443 → CC:8443 |
| BTP → on-premises ABAP | BTP Connectivity → CC tunnel → localhost:50000 |
The Cloud Connector is included in the sapse/abap-cloud-developer-trial:2023
image and runs as a separate Java process inside the same container.
Table of Contents¶
- Prerequisites
- Server Setup
- SAP ABAP Trial Container
- Pulling the Image
- Starting the Container
- Disk Space Warning
- SAP System Configuration
- License Installation
- Work Process Tuning
- User Access
- Unlocking the DEVELOPER User
- HTTPS / Reverse Proxy Setup
- Cloud Connector Setup
- Starting Cloud Connector
- Nginx HTTPS Proxy for CC Admin
- Initial CC Setup
- Connecting CC to BTP
- Adding a System Mapping
- Adding Resources
- Password Reset
- Integration Tests
- Running Locally
- Test Categories
- Skipped Tests
- Known Test Failures
- Running a Specific Test
- GitHub Actions CI
- Workflow Overview
- GitHub Secrets Setup
- CI-Specific Considerations
- Troubleshooting
Prerequisites¶
- A Linux server with at least 16 GB RAM, 4 CPU cores, and 150 GB disk (the SAP container image is ~80 GB compressed).
- Docker (or Podman) installed.
- Root or
sudoaccess on the server. - A DNS A record pointing a subdomain at the server IP (for HTTPS).
- A SAP license file for your hardware key (obtain from the SAP trial portal).
Server Setup¶
Install Docker¶
Verify disk space¶
The SAP image is large. Confirm there is sufficient space before pulling:
SAP ABAP Trial Container¶
Pulling the Image¶
The official SAP ABAP Cloud Developer Trial image is available from Docker Hub
under the sapse organisation:
Note:
podmancan be used as a drop-in replacement. If you get a disk- full error from podman's/var/tmpoverlay, ensure the underlying partition has enough space or reconfigure the podman storage driver.
Starting the Container¶
docker run -d \
--name a4h \
--hostname vhcala4hci \
-p 50000:50000 \
-p 50001:50001 \
-p 8443:8443 \
-p 30213:30213 \
--sysctl net.ipv4.ip_local_port_range="40000 60999" \
--sysctl kernel.shmmax=21474836480 \
--sysctl kernel.shmmni=32768 \
--sysctl kernel.shmall=5242880 \
-v /data/sap/sysvol:/sysvol \
sapse/abap-cloud-developer-trial:2023
Key parameters:
| Parameter | Purpose |
|---|---|
--hostname vhcala4hci |
SAP requires a specific hostname |
-p 50000:50000 |
SAP ICM HTTP port (ADT, browser access) |
-p 50001:50001 |
SAP ICM HTTPS port |
-p 8443:8443 |
Alternative HTTPS |
-p 30213:30213 |
HANA SQL port (multitenant tenant DB) |
--sysctl ... |
Required kernel parameters for SAP/HANA |
-v /data/sap/sysvol:/sysvol |
Persistent volume for SAP data |
Disk Space Warning¶
If you see:
This means the partition hosting/var/tmp or the podman overlay is full.
Either free space or move Docker/Podman storage to a larger partition.
Verifying the Container is Up¶
The SAP system takes 5-10 minutes to fully start. Check readiness:
# Watch SAP startup progress
docker exec a4h /usr/sap/hostctrl/exe/sapcontrol -nr 00 -function GetProcessList
# Quick HTTP ping (expects 403 when SAP is up)
curl -s -o /dev/null -w "%{http_code}" http://localhost:50000/sap/bc/ping
SAP is ready when sapcontrol GetProcessList shows all processes as Running.
SAP System Configuration¶
License Installation¶
The trial image ships without a permanent license. Obtain a permanent license from the SAP trial portal for your hardware key.
Find your hardware key:
docker exec a4h /usr/sap/A4H/SYS/exe/run/saplikey \
pf=/usr/sap/A4H/SYS/profile/A4H_D00_vhcala4hci \
-get
Note the Hardware Key from the output and request a license file from the
SAP trial portal.
Install the license:
# Copy license file into container
docker cp /path/to/A4H_license.txt a4h:/tmp/A4H_license.txt
# Install all keys from the file
docker exec a4h /usr/sap/A4H/SYS/exe/run/saplikey \
pf=/usr/sap/A4H/SYS/profile/A4H_D00_vhcala4hci \
-install /tmp/A4H_license.txt
# Verify installation
docker exec a4h /usr/sap/A4H/SYS/exe/run/saplikey \
pf=/usr/sap/A4H/SYS/profile/A4H_D00_vhcala4hci \
-get
The correct profile path inside the container is:
Common mistake: The profile is
A4H_D00_vhcala4hci, notA4H_DVEBMGS00_vhcala4hci. Listls /usr/sap/A4H/SYS/profile/to confirm the correct filename ifsaplikeyreports a missing profile error.
Work Process Tuning¶
The default SAP profile only allocates 7 dialog work processes. Running the full integration test suite (34 tests) exhausts these quickly and causes 503 errors. Increase them:
Edit the instance profile inside the container:
Change:
To:Session Timeout Tuning¶
ADT CRUD operations open stateful sessions (locks) that hold a dialog work process in PRIV (private) mode. If the client disconnects without explicitly ending the session, the WP stays occupied until the timeout expires.
The default timeout is 600 seconds (10 minutes), which means 30+ integration tests can exhaust all work processes before the first sessions expire.
Add these parameters to the instance profile:
# Aggressive session cleanup for CI / remote ADT clients
rdisp/plugin_auto_logout = 120
rdisp/max_wprun_time = 300
icm/keep_alive_timeout = 60
http/security_session_timeout = 120
| Parameter | Value | Effect |
|---|---|---|
rdisp/plugin_auto_logout |
120 | Auto-logout idle HTTP plugin sessions after 2 min |
rdisp/max_wprun_time |
300 | Max runtime for a single dialog step (5 min) |
icm/keep_alive_timeout |
60 | Close idle HTTP keep-alive connections after 1 min |
http/security_session_timeout |
120 | HTTP security session timeout (2 min) |
Without these settings, stale PRIV sessions from failed or disconnected tests accumulate and cause 503 errors for subsequent requests.
Restart the ABAP application server (not the whole container):
# Stop ABAP only
docker exec a4h /usr/sap/hostctrl/exe/sapcontrol -nr 00 -function Stop
# Wait ~60s for full stop
docker exec a4h /usr/sap/hostctrl/exe/sapcontrol -nr 00 -function Start
Note:
RestartInstancedid not work reliably; use explicitStopthenStart.
User Access¶
The trial system ships with these pre-configured users:
| User | Default Password | Role |
|---|---|---|
DEVELOPER |
ABAPtr2023#00 |
ABAP developer (S_DEVELOP auth) |
DDIC |
ABAPtr2023#00 |
Data dictionary admin |
BWDEVELOPER |
ABAPtr2023#00 |
BW developer |
Use DEVELOPER for ADT and integration tests. DDIC does not have the
S_DEVELOP authorization object required to create/edit ABAP objects via ADT.
Unlocking the DEVELOPER User¶
After many failed login attempts, the DEVELOPER user gets locked
(UFLAG = 128 in USR02). This manifests as HTTP 401 from ADT endpoints even
though /sap/bc/ping returns 403 (ping uses a lighter auth check).
Unlock via HANA SQL (no HANA SYSTEM password required):
The a4hadm OS user has a pre-configured HANA userstore key that connects as
the ABAP schema owner (SAPA4H):
docker exec -it a4h bash
su - a4hadm
# Connect to the HANA tenant DB as SAPA4H
hdbsql -U DEFAULT -d HDB
# Unlock DEVELOPER
UPDATE SAPA4H.USR02 SET UFLAG = 0 WHERE BNAME = 'DEVELOPER';
# Verify
SELECT BNAME, UFLAG, PWDSTATE FROM SAPA4H.USR02
WHERE BNAME IN ('DEVELOPER', 'DDIC');
\q
UFLAG = 0 means unlocked. UFLAG = 128 means locked by too many failed
logon attempts. PWDSTATE = 1 means the user must change password on next
login (leave as-is; ADT handles this transparently).
Alternative: If you have access to SAP GUI or ABAP Developer Tools, use transaction
SU01to unlock users without direct HANA access.
HTTPS / Reverse Proxy Setup¶
Expose the SAP system over HTTPS via Nginx and Let's Encrypt.
Install Nginx and Certbot¶
Configure Nginx Reverse Proxy¶
Create /etc/nginx/sites-available/<your-subdomain>:
server {
listen 80;
server_name <your-subdomain>;
location / {
proxy_pass http://localhost:50000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
client_max_body_size 50m;
}
}
Enable the site:
ln -s /etc/nginx/sites-available/<your-subdomain> /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
Obtain Let's Encrypt Certificate¶
Certbot will automatically update the Nginx config with SSL settings and set up auto-renewal via a systemd timer.
DNS propagation: Run certbot only after the DNS A record has propagated (verify with
dig <your-subdomain>). Let's Encrypt will fail with a challenge error if the record hasn't propagated yet.
Cloud Connector Setup¶
SAP Cloud Connector (CC) is bundled with the sapse/abap-cloud-developer-trial:2023
image. It allows BTP services (Connectivity, Destination) to reach the
on-premises ABAP system through an outbound tunnel — no inbound firewall rules
needed.
Starting Cloud Connector¶
CC is not started automatically when the Docker container boots. Start it once after the container is up:
CC logs to /opt/sap/scc/scc_daemon.log inside the container and listens on
https://vhcala4hci:8443 (the container's hostname). To verify it started:
Note: CC does not automatically restart when the container restarts. Add the
rcscc_daemon startcall to your container startup script or run it manually after each container restart.
Nginx HTTPS Proxy for CC Admin¶
The CC admin UI is served over HTTPS with a self-signed certificate. Browsers block XHR calls to self-signed certificates even after clicking "proceed", which breaks the CC admin panel's JavaScript entirely.
The fix is an nginx HTTPS-to-HTTPS reverse proxy: nginx terminates TLS with the
trusted Let's Encrypt certificate and forwards requests to CC's self-signed
backend with proxy_ssl_verify off. The browser sees the trusted cert; CC
still handles authentication internally.
Add this server block to your nginx site config
(/etc/nginx/sites-enabled/<your-subdomain>):
server {
listen 8443 ssl;
server_name <your-subdomain>;
ssl_certificate /etc/letsencrypt/live/<your-subdomain>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<your-subdomain>/privkey.pem;
location / {
proxy_pass https://172.17.0.2:8443;
proxy_ssl_verify off;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "";
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
}
Open port 8443 in the firewall:
The CC admin panel is then accessible at https://<your-subdomain>:8443.
Why not TCP stream pass-through? A plain TCP proxy (
streammodule) forwards CC's self-signed certificate directly to the browser. The browser accepts the initial page load after a manual "proceed" click, but blocks all subsequent XHR/fetch calls withERR_CERT_AUTHORITY_INVALID. The HTTPS reverse proxy solves this completely.
Initial CC Setup¶
On first access, CC shows an Initial Setup wizard.
- Navigate to
https://<your-subdomain>:8443and log in: - Username:
Administrator - Password:
manage - You will be prompted to change the password. Set a strong password and save it.
- On the Installation Type screen, select Master (Primary Installation).
- Complete the wizard. CC saves
<haRole>master</haRole>in its config.
If the wizard does not appear (CC jumps directly to the dashboard), the initial setup was already completed in a previous session.
Connecting CC to BTP¶
In the CC admin panel, go to Define Subaccount → On-Premises to Cloud and click + Add Subaccount.
Step 1 — HTTPS Proxy: Leave all fields empty (no proxy needed) and click Next.
Step 2 — BTP Subaccount details:
| Field | Value |
|---|---|
| Region | cf.us10-001.hana.ondemand.com |
| Subaccount | Your BTP subaccount GUID (find it in the BTP Cockpit URL or via btp list accounts/subaccount) |
| Display Name | Any label, e.g. dev |
| Login | Your BTP user (e.g. S-User or email) |
| Password | Your BTP password |
Click Next, then Finish. CC will establish the outbound tunnel to BTP. The status dot next to the subaccount turns green when the tunnel is active.
BTP Prerequisites: The BTP subaccount must have the Connectivity entitlement assigned. The
connectivity/liteservice instance must exist in the subaccount before the tunnel can be established. Create it manually in the BTP Cockpit (Service Marketplace → Connectivity → Create with planlite).
Adding a System Mapping¶
Once the subaccount tunnel is active, map the on-premises ABAP system so BTP can route requests to it.
In the CC admin panel, go to Cloud to On-Premises and click + Add. Walk through the wizard:
| Step | Field | Value |
|---|---|---|
| Protocol | Protocol | HTTP |
| Back-end Type | Back-end Type | ABAP System |
| Internal Host | Internal Host | localhost |
| Internal Host | Internal Port | 50000 |
| Virtual Host | Virtual Host | a4h-abap |
| Virtual Host | Virtual Port | 50000 |
| Host Header | Host in Request Header | Use Internal Host |
Virtual Host is the name BTP uses to refer to this system in Destinations. Internal Host is the real address as seen from CC inside the container. Use
Use Internal Hostfor the request header so the ABAP system seeslocalhost:50000in theHostheader, which matches its ICM configuration.
Click Finish.
Adding Resources¶
After saving the system mapping, CC shows it in the list with a warning that no resources are accessible yet. Click the system mapping row, then click + Add under Resources.
| Field | Value |
|---|---|
| URL Path | / |
| Access Policy | Path and all sub-paths |
| Description | All ADT/OData paths |
Click Save. The system mapping is now fully configured.
Password Reset¶
If the CC admin password is lost or the account is locked, reset it directly
in users.xml inside the container:
# Stop CC
docker exec a4h bash -c "rcscc_daemon stop"
# Compute SHA-256 of new password (replace "manage" with your desired password)
NEW_PASS=$(echo -n 'manage' | sha256sum | awk '{print $1}' | tr '[:lower:]' '[:upper:]')
echo "Hash: $NEW_PASS"
# Write users.xml with the new password
docker exec a4h bash -c "cat > /opt/sap/scc/config/users.xml << 'EOF'
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users xmlns=\"http://tomcat.apache.org/xml\"
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xsi:schemaLocation=\"http://tomcat.apache.org/xml tomcat-users.xsd\"
version=\"1.0\">
<role rolename=\"admin\"/>
<group groupname=\"initial\" roles=\"\"/>
<user username=\"Administrator\" password=\"$NEW_PASS\" groups=\"\" roles=\"admin\"/>
</tomcat-users>
EOF"
# Start CC again
docker exec a4h bash -c "rcscc_daemon start"
Important: The
roles="admin"attribute on the<user>element is required. If it is missing or set toroles="", Tomcat returns HTTP 408 on every login attempt. Thegroups=""attribute must also be empty (notgroups="initial") to avoid inheriting the group's empty role set.
If the CC initial setup needs to be reset as well (not just the password):
docker exec a4h bash -c "rcscc_daemon stop"
docker exec a4h rm -f /opt/sap/scc/scc_config/scc_config.ini \
/opt/sap/scc/scc_config/scc_config.stamp
docker exec a4h bash -c "rcscc_daemon start"
This forces the Initial Setup wizard to appear again on next login.
Integration Tests¶
Running Locally¶
The integration tests are gated by the integration build tag and require four
environment variables:
export SAP_URL=https://<your-subdomain> # or http://<ip>:50000
export SAP_USER=DEVELOPER
export SAP_PASSWORD='ABAPtr2023#00'
export SAP_CLIENT=001
npm run test:integration
The tests:
- Create temporary ABAP objects in the $TMP package
- Exercise the full ADT API surface (read, write, activate, unit tests, etc.)
- Clean up all created objects after each test via deferred cleanup functions
- Use the DEVELOPER user (not DDIC — see User Access)
Test Categories¶
The integration test suite covers these areas:
| Category | Tests | Description |
|---|---|---|
| Read operations | SearchObject, GetProgram, GetClass, GetTable, GetTableContents, RunQuery, GetPackage | Basic ADT read APIs |
| CDS / RAP | GetCDSDependencies, GetDDLS, GetBDEF, GetSRVB, GetSource_RAP | CDS views, behavior definitions, service bindings |
| CRUD | CRUD_FullWorkflow, LockUnlock, WriteProgram, WriteClass, CreateAndActivateProgram, CreateClassWithTests, EditSource, CreatePackage | Create, lock, modify, activate, delete ABAP objects |
| Dev tools | SyntaxCheck, SyntaxCheckWithErrors, RunUnitTests, PrettyPrint, GetPrettyPrinterSettings | Syntax checker, unit test runner, pretty printer |
| Code intelligence | CodeCompletion, FindReferences, FindDefinition, GetTypeHierarchy | Code completion, where-used, navigation |
| RAP E2E | RAP_E2E_OData | End-to-end: DDLS → SRVD → SRVB → publish |
| Debugger | ExternalBreakpoints, DebuggerListener, DebugSessionAPIs | External breakpoints and debug sessions (skipped in CI) |
| Namespaces | Namespace_GetSource_Class, _Interface, _Program, _Function, _DDLS, _BDEF | Namespaced objects (/DMO/, /UI5/, /AIF/) |
Skipped Tests¶
The following tests are automatically skipped in CI and must be run manually:
| Test | Reason | Manual Run Command |
|---|---|---|
TestIntegration_ExternalBreakpoints |
Requires interactive debug session; breakpoint API needs specific user authorization | npm run test:integration -- --grep ExternalBreakpoints |
TestIntegration_DebuggerListener |
Requires a debuggee (running ABAP program hitting a breakpoint) to catch | npm run test:integration -- --grep DebuggerListener |
TestIntegration_DebugSessionAPIs |
Tests debug attach/step/stack APIs that need an active debug session | npm run test:integration -- --grep DebugSessionAPIs |
These tests are skipped with t.Skip() because debugger operations require
interactive sessions that cannot be reliably automated. They still exist in the
test file and can be run manually for local development.
Known Test Failures¶
| Test | Status | Reason |
|---|---|---|
TestIntegration_RAP_E2E_OData |
May FAIL on fresh systems | The test creates a DDLS, SRVD, and SRVB (ZTEST_MCP_SB_FLIGHT), then publishes the service binding. The GetSRVB verification step may return HTTP 500 immediately after publish due to SAP internal timing. The test retries once after a 3-second delay, but this may still fail on slow systems. On subsequent runs the SRVB already exists, so the test handles the "already exists" error gracefully. |
All other tests should pass on a correctly configured trial system with the work process and session timeout tuning described above.
Running a Specific Test¶
Running Tests Without Debugger Tests¶
To explicitly exclude debugger tests (they are already skipped, but for clarity):
GitHub Actions CI¶
Workflow Overview¶
The workflow is defined in .github/workflows/test.yml:
push / pull_request / workflow_dispatch
│
├── unit (ubuntu-latest)
│ ├── npm test ← all unit tests
│ └── npm run build ← verify TypeScript builds
│
└── integration (ubuntu-latest) [needs: unit]
├── condition: PR, push to main, or manual dispatch
├── environment: sap-trial ← uses GitHub environment secrets
└── npm run test:integration
The integration job only runs when:
- A pull request is opened/updated
- A push lands on main
- The workflow is manually dispatched with run_integration: true
GitHub Secrets Setup¶
Integration tests read credentials from GitHub environment secrets in the
sap-trial environment.
Create the environment:
Set the four secrets:
gh secret set SAP_URL --env sap-trial --repo <owner>/<repo> --body "https://<your-subdomain>"
gh secret set SAP_USER --env sap-trial --repo <owner>/<repo> --body "DEVELOPER"
gh secret set SAP_PASSWORD --env sap-trial --repo <owner>/<repo> --body "ABAPtr2023#00"
gh secret set SAP_CLIENT --env sap-trial --repo <owner>/<repo> --body "001"
Verify:
Trigger a manual run with integration tests:
CI-Specific Considerations¶
Node.js 24 opt-in: The workflow sets FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true
at the top level to silence GitHub Actions deprecation warnings about Node.js 20.
The actions/checkout@v4 and actions/setup-go@v5 actions run on Node.js 20 by
default; this env var forces Node.js 24 ahead of GitHub's mandatory cutover.
Go module cache disabled: The workflow uses cache: false for
actions/setup-go because the Go toolchain download can cause tar extraction
warnings (/usr/bin/tar: ... Cannot open: File exists) when the cache is
restored. These warnings are harmless but noisy.
Test timeout: Integration tests use -timeout 10m to account for network
latency between GitHub Actions runners and the SAP system. Individual ADT calls
from a remote CI runner take longer than from a local machine.
Debugger tests auto-skip: The 3 debugger tests (ExternalBreakpoints,
DebuggerListener, DebugSessionAPIs) call t.Skip() unconditionally in CI.
They require interactive debug sessions that cannot be automated.
Session exhaustion prevention: The SAP system must have the session timeout tuning from Session Timeout Tuning applied. Without it, the 30+ sequential integration tests accumulate stale PRIV sessions on the SAP server, eventually exhausting all dialog work processes and causing 503 errors for the remaining tests. This is especially pronounced in CI where network latency is higher and HTTP connections take longer to complete.
Troubleshooting¶
SAP returns 401 on ADT but 403 on /sap/bc/ping¶
The user is locked (UFLAG=128). ADT enforces strict auth and rejects locked
users immediately; the lightweight /sap/bc/ping service returns 403 (auth
succeeded but no authorisation) for the same locked user.
Fix: Unlock the DEVELOPER user via HANA SQL.
Integration tests fail with 503 mid-run¶
This is caused by dialog work process exhaustion. Two things must be configured:
- Enough work processes: Set
rdisp/wp_no_dia = 25(see Work Process Tuning). - Session timeouts: Add the session cleanup parameters (see Session Timeout Tuning). Without them, stale PRIV sessions from CRUD tests hold work processes for up to 10 minutes.
To diagnose, check the work process table:
Look for DIA work processes in Stop, PRIV status — these are held by stale
sessions. If most DIA WPs are PRIV, that explains the 503 errors.
saplikey: profile not found¶
List the actual profile files:
Use the A4H_D00_vhcala4hci file, not A4H_DVEBMGS00_vhcala4hci.
HANA SYSTEM password unknown¶
Use the a4hadm userstore key instead. It connects as SAPA4H (the ABAP
schema owner) without needing the SYSTEM password:
Build fails: TypeScript compilation errors¶
If you see TypeScript errors during npm run build, ensure all dependencies
are installed with npm ci and you're using Node.js 20+.
DDIC user returns 403 on CRUD operations¶
The DDIC user does not have the S_DEVELOP authorization object. Use the
DEVELOPER user for all ADT and integration test operations. See
User Access.
RAP E2E test fails with "does already exist"¶
The SRVB was created by a previous test run and not cleaned up. The test now
handles this gracefully by catching the "already exists" error and continuing.
If it still fails, manually delete the object via ADT or SAP GUI (transaction
SE80).
RAP E2E test fails with 500 on GetSRVB after publish¶
SAP may return HTTP 500 immediately after publishing a service binding. The test includes a retry with a 3-second delay, but this can still fail on slow systems. This is a known SAP timing issue and does not indicate a real problem — the SRVB was created and published successfully.
Container starts but SAP is not ready after 10 minutes¶
Check the container logs:
Look for HANA startup errors. Common causes:
- Insufficient shared memory (kernel.shmmax sysctl not set)
- Disk full during HANA startup
HTTPS certificate errors in integration tests¶
If using a self-signed cert or testing against HTTP, set:
or use the plain HTTP URL (http://server-ip:50000). Let's Encrypt certificates
do not require SAP_INSECURE.
X.509 Certificate Authentication Setup (mTLS)¶
This section describes how to configure the SAP trial system for X.509 client certificate authentication. This is required for testing mTLS and principal propagation features.
Generate Test CA and Client Certificate¶
# Generate CA (self-signed, for testing only)
openssl genrsa -out ca.key 4096
openssl req -new -x509 -key ca.key -out ca.crt -days 365 \
-subj "/CN=arc1-test-ca/O=arc1 testing"
# Generate client certificate for the DEVELOPER user
openssl genrsa -out developer.key 2048
openssl req -new -key developer.key -out developer.csr \
-subj "/CN=DEVELOPER"
openssl x509 -req -in developer.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out developer.crt -days 365
# Verify the certificate
openssl x509 -in developer.crt -text -noout | grep Subject
# Expected: Subject: CN = DEVELOPER
Import CA into SAP STRUST¶
The CA certificate must be added to the SAP system's trust store so it can verify client certificates signed by this CA.
Option A: Via SAP GUI (if available)
- Open transaction
/nSTRUST - Navigate to SSL Server Standard PSE
- Click Import in the Certificate section
- Paste the content of
ca.crt - Click Add to Certificate List
- Save
Option B: Via HANA SQL (for headless trial system)
The trial system may not have SAP GUI access. In this case, use the HANA SQL approach to insert the certificate directly:
docker exec -it a4h bash
su - a4hadm
# Copy the CA cert content (base64 encoded)
cat /path/to/ca.crt | base64 -w0
# Use sapgenpse to import (if available)
# Or use the STRUST-related ABAP program via SM38
Note: Direct STRUST manipulation via SQL is complex. The recommended approach is to use SAP GUI or ADT's STRUST functionality. If you have ADT access from Eclipse, you can use the STRUST transaction there.
Configure SAP Profile for Certificate Login¶
Edit the instance profile inside the container:
Add these parameters:
# Enable rule-based certificate mapping (allows CERTRULE to work)
login/certificate_mapping_rulebased = 1
# Accept client certificates during TLS handshake
# 0 = don't request, 1 = request (optional), 2 = require
icm/HTTPS/verify_client = 1
Configure Certificate Mapping Rule (CERTRULE)¶
This tells SAP how to map the certificate's Subject CN to a SAP user.
- Open transaction
/nCERTRULEin SAP GUI or ADT - Import the client certificate (
developer.crt) - Create a rule:
- Certificate Attribute:
Subject CN - Login As:
Use CN value as SAP username - Save and activate
Restart SAP ICM¶
After profile and CERTRULE changes:
# Restart ABAP (not the whole container)
docker exec a4h /usr/sap/hostctrl/exe/sapcontrol -nr 00 -function Stop
# Wait ~60s
docker exec a4h /usr/sap/hostctrl/exe/sapcontrol -nr 00 -function Start
Test Certificate Authentication¶
# Test with curl (using the HTTPS port)
curl --cert developer.crt --key developer.key \
--cacert ca.crt \
"https://<your-subdomain>/sap/bc/adt/core/discovery?sap-client=001"
# Test with arc1
npx arc-1 --url https://<your-subdomain> \
--client-cert developer.crt \
--client-key developer.key \
--ca-cert ca.crt
# If using the trial system's Let's Encrypt cert (no --ca-cert needed):
npx arc-1 --url https://<your-subdomain> \
--client-cert developer.crt \
--client-key developer.key
Important: The
--ca-certflag is for trusting the SAP server certificate. If your SAP system uses Let's Encrypt (as configured in the HTTPS section above), the system's default CA store already trusts it and--ca-certis not needed. The client certificate (--client-cert) is what SAP uses to authenticate the user — these are two different certificates for two different purposes.
Principal Propagation Test Setup¶
To test principal propagation (OIDC → ephemeral X.509), the SAP configuration is the same as above. The CA in STRUST is the same CA that signs the ephemeral certificates.
# Test ephemeral cert generation + SAP auth
npx arc-1 --url https://<your-subdomain> \
--pp-ca-key ca.key \
--pp-ca-cert ca.crt \
--oidc-issuer https://login.microsoftonline.com/{tenant-id}/v2.0 \
--oidc-audience api://arc1 \
--transport http-streamable
For full OIDC + principal propagation testing, you also need an EntraID app registration. See docs/enterprise-auth.md for the complete setup guide.