Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
Showing results for 
Search instead for 
Did you mean: 
Active Participant
Note:  If you're renewing a custom domain certificate, check out this accompanying blog post.

Renewing Your Custom Domain Certificate For Multi-Target Applications


While there are a couple of other great posts for configuring custom domains in cloud foundry,

Demystifying SAP Cloud Platform Custom Domains

Fun and Games with SAP Cloud Domains

... and with all the emphasis on creating multitenant SaaS solutions that integrate with SAP's cloud offerings (read, make money), I wanted to make sure I could put together an example of all that's needed to support this exact scenario.  The following is the set of steps I took to accomplish this exact task for a sample project I'm working on(  I didn't take to time to generalize the domain name in this example so you'll need to refactor it for your purposes.  For the most part, a simple search/replace exercise in the project which can be found here is all that should be needed.

I'll try to explain where this scenario is a bit more complicated than that for a single hostname, but most of this post will be screen shots and command line usage.

How multitenant apps work in the context of SAP Cloud Foundry.

Before we get started, it's important to understand a bit of how these types of applications exist in our cloud foundry environment.  Cloud Foundry application execution is in a SHARED namespace environment even when the app itself runs in it's own isolated environment(container).  As such some things need to be unique within the whole cloud foundry landscape.  A multitenant app lives within a space within a subaccount within a master account on the landscape.  It's designed in a way that it can field subscription/unsubscription requests and be registered to do so.  When a client subscribes to your multitenant application, they get a unique hostname that's based on your custom domain.  That way when your client's users access their tenant(subscription) they can be indentified as belonging to that client.  I'm using client here to mean the client of the SaaS solution that you(likely a SAP partner/customer) have built and not you the customer of SAP.  Each client will be given their own subaccount of your master account so that they can connect to their own identity provider(and manage their own users).  Each subaccount has it's own subdomain which is an identifier used in the authentication mechanism and must be unique within the lanscape.  It is this subdomain name concatenated with your custom domain name that forms the client's hostname for their subscription.  Again, I'll use my sample project to illustrate.

Developing Multitenant Business Applications in the Cloud FoundryEnvironment = Main web entry point for static content. = Hostname for administrative use of the application.(the subdomain conciletime is used for the main subaccount where the actual application lives.  It happens to be the same as the name, but doesn't have to be) = A subscriber client that has a subaccount with the subdomain name client1.  Note again that this subdomain name must be unique within the entire landscape so once claimed nobody else can use it.  For this reason, don't be surprised if client1 is already taken.  This is likely to occur if your client has subscribed to any other multitenant app on the landscape. = A more reasonable convention to use when signing up subscribers to your multitenant application.  By prefixing the client with "ct-" makes it more likely that the subdomain won't already be taken, but doesn't guarantee it.  You'll need to keep this in mind as well.

By this point you should realize that you're going to need to support * because you can't know ahead of time what subdomains will be available for your clients.  This is important when it comes to purchasing the SSL certificate you'll need to protect your application.

Official docs.

Creating Custom Domains with TLS/SSL Server Authentication

Buy custom domain quota

In order to create a custom domain in Cloud Foundry you need a quota for doing so.  Depending on your account you might be able to do this yourself(CPEA) but more likely you'll have to purchase this from your SAP salesperson.


Buy the domain

We'll assume you've already done this and have access to the DNS administrative tool or access to the IT person who does.  There are plenty of domain registrars out there, I used GoDaddy.


Create the custom domain

If you're scared of command line tools you'll need to stop here because there seems to be currently no way to do this through the cloud cockpit UI.  If you don't have the cf cli got get it for your platform.

Getting Started with SAP Cloud Platform Cloud Foundry Environment

  1. Download and install the Cloud Foundry CLI

IMPORTANT: Dowload and install the custom domain CF CLI Plugin.

  • Custom Domain Self-service - Manage TLS server certificates and client authentication trust for custom domains

Follow the documentation for details.

Once you've got things installed, get connected to your account landscape's api endpoint and login.

Target the organization where you'll create your custom domain (don't forget you need a quota, look above for info).
cf t -o ConcileTime

Now create your domain name in your organization.
cf create-domain ConcileTime

Creating domain for org ConcileTime as


Check that your domain got created properly.

cf domains

Getting domains in org ConcileTime as

name                               status type       shared  shared

apps.internal                       shared                     owned


Generate private key and CSR

Now you need to create a special domain key.  This is an encryption key that will be used to create your Certificate Signing Request(CSR).  You'll need to supply some details and list the domain names you'll use with the resultant certificate.  "C=US, ST=State, O=ConcileTime, CN=*"  Be sure that the CN value contains an asterix(*) or the certificate won't work for all possible hostnames generated for your domain name.
cf custom-domain-create-key ComodoConcileTimeKey "C=US, ST=State, O=ConcileTime, CN=*" --verbose

Command: custom-domain-create-key

Organisation:  ConcileTime  (4d641712-8d17-45c6-adca-65c4f61e4202)

API Endpoint:

Default API Server:


Subject: C=US, ST=State, O=ConcileTime, CN=*

Domain Names: 

Host Names:

Are you sure to generate this key in the system? (y/N)


DEBUG:2019/07/30 14:22:07 client.go:100: POST to

DEBUG:2019/07/30 14:22:07 client.go:105: Request: [{ ComodoConcileTimeKey C=US, ST=State, O=ConcileTime, CN=* []  }]

DEBUG:2019/07/30 14:22:14 client.go:129: HTTP Status: 202

DEBUG:2019/07/30 14:22:14 client.go:130: Response: [{"guid":"173006fd-5f0d-4ac4-a3e7-980c8739bfd6","alias":"ComodoConcileTimeKey","subject":"C=US, ST=State, O=ConcileTime, CN=*","dns":[""]}]

Successfully created key request with name: ComodoConcileTimeKey

The private key will be generated in the system. This operation will take some time!

Call custom-domain-get-csr now to get the corresponding certificate signing request

cf custom-domain-get-csr ComodoConcileTimeKey csr.pem

Download the CSR

Now get the CSR with the following command. Save the certificate text somewhere safe as you'll need it later.
cf custom-domain-get-csr ComodoConcileTimeKey comodo_conciletime_csr.pem

Command: custom-domain-get-csr

Organisation:  ConcileTime  (4d641712-8d17-45c6-adca-65c4f61e4202)

API Endpoint:

Default API Server:






Send the CSR to get signed

Purchasing a wildcard SSL certificate.

I'm going to assume you already have a domain name that you can use for this purpose.  If you need to you can have your DNS administrator create a new subdomain on your domain name (ex. but to keep things as clear as possible, I'll create a wildcard certificate for a single level of domain matching on my domain name.  It is possible to create a SSL wildcard certificate for multiple levels of subdomain(ex. *.* but let's keep it simple.

You'll need to grab your manager's credit card for the following.  While it's possible to create SSL certificates using your own custom certificate authority, that's beyond the scope of this post and requires that every system that accesses your application install and trust your certificate authority(something IT admins are reluctant to do).  Anyway, the point it to look like a legitimate business.  Here's the link to official docs.

Creating Custom Domains with TLS/SSL Server Authentication

You're looking for the Positive SSL Wildcard certificate.

Add it to your cart.

Put in your Billing Address and Credit Card Detail (Omitted).  Confirm and Complete the Order.

You'll be prompted to set a password for your account with Comodo.

Next generate your certificate.  Click GENERATE CERT NOW

Select Order Type.

I used the CNAME method for authentication.  Basically they want you to prove that you are creating a certificate for a domain name that you actually own and not someone else's.

Now take the plaintext of the CSR you generated above and paste it here in Step #4.

Select a couple other options and select OTHER as the server type.  Click Continue.

Continue with the process.  MAKE SURE THAT THE DOMAIN NAME HAS AN ASTERIX * !

Continue looking over the form and verify that everything is correct.

If all looks correct, Click Continue.

You've now completed the request.

Pay special attention to the instructions for creating a DNS CNAME entry.  This is needed to confirm that you are authorized to makes requests for your domain name.

Log into or ask your IT admin to make a CNAME record in your domain administration tool.  Again, I'll use GoDaddy since that's where I registered my domain.

You may have to wait a bit for the DNS change to trickle through the Internet.  Then you can test to be sure the changes took.

; <<>> DiG 9.10.6 <<>>
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 28823
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
; EDNS: version: 0, flags:; udp: 4096
; IN A
;; AUTHORITY SECTION: 600 IN SOA 2019070802 1800 1200 1814400 5400
;; Query time: 117 msec
;; WHEN: Tue Jul 30 13:44:51 EDT 2019
;; MSG SIZE rcvd: 250

After a few minute, check your email box.  You should get an email with an attachment containing your certificate,

From: Sectigo Certification Authority <>

Date: Tuesday, July 30, 2019 at 1:48 PM

To: "Lunde, Andrew" <>

Subject: ORDER #25500XXXX - Your PositiveSSL Wildcard Certificate for *


Your PositiveSSL Wildcard Certificate for * is attached!


Thank you for placing your order. We are pleased to announce that your PositiveSSL Wildcard Certificate for * has been issued.

To help reduce domain name mismatch warnings, we have also included the domain name in your certificate.

We strongly recommend that you click here for instructions to ensure that your certificate is installed and your webserver is configured correctly.

Attached to this email you should find a .zip file containing:

  • Root CA Certificate - AddTrustExternalCARoot.crt

  • Intermediate CA Certificate - USERTrustRSAAddTrustCA.crt

  • Intermediate CA Certificate - SectigoRSADomainValidationSecureServerCA.crt

  • Your PositiveSSL Wildcard Certificate - STAR_conciletime_com.crt

You can also find your PositiveSSL Wildcard Certificate for * in text format at the bottom of this email.

Should you have any questions or issues you would like to discuss, please do not hesitate to contact us.

Thank you for being a valued Sectigo customer.


visit our website

get support

Copyright Ⓒ Sectigo Limited, All rights reserved.

Your PositiveSSL Wildcard Certificate for * in text format (if required):










Download and unzip the files locally.  You should see the 4 crt files mentioned in the email.

You'll need to concatenate these files together before uploading them.
cat STAR_conciletime_com/AddTrustExternalCARoot.crt > comodo-conciletime-certchain.pem
cat STAR_conciletime_com/USERTrustRSAAddTrustCA.crt >> comodo-conciletime-certchain.pem
cat STAR_conciletime_com/SectigoRSADomainValidationSecureServerCA.crt >> comodo-conciletime-certchain.pem
cat STAR_conciletime_com/STAR_conciletime_com.crt >> comodo-conciletime-certchain.pem


Upload certificate

Use the cf upload command to upload the composite certificate bundle you just created.
cf custom-domain-upload-certificate-chain ConcileTimeDomainKey comodo-conciletime-certchain.pem

Command: custom-domain-upload-certificate-chain

Organisation:  ConcileTime  (4d641712-8d17-45c6-adca-65c4f61e4202)

API Endpoint:

Default API Server:

Key: ComodoConcileTimeKey

Subject:CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE

Issuer:CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE


Not Before:Tue May 30 10:48:38 UTC 2000

Not After:Sat May 30 10:48:38 UTC 2020










Subject:CN=USERTrust RSA Certification Authority,O=The USERTRUST Network,L=Jersey City,ST=New Jersey,C=US

Issuer:CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE


Not Before:Tue May 30 10:48:38 UTC 2000

Not After:Sat May 30 10:48:38 UTC 2020













Subject:CN=Sectigo RSA Domain Validation Secure Server CA,O=Sectigo Limited,L=Salford,ST=Greater Manchester,C=GB

Issuer:CN=USERTrust RSA Certification Authority,O=The USERTRUST Network,L=Jersey City,ST=New Jersey,C=US


Not Before:Fri Nov  2 00:00:00 UTC 2018

Not After:Tue Dec 31 23:59:59 UTC 2030










Subject: CN=*,OU=DomainControl Validated+OU=PositiveSSL Wildcard

Subject Alternative Names:

  DNSName: *


Issuer:CN=Sectigo RSA Domain Validation Secure Server CA,O=Sectigo Limited,L=Salford,ST=Greater Manchester,C=GB


Not Before:Tue Jul 30 00:00:00 UTC 2019

Not After:Wed Jul 29 23:59:59 UTC 2020












Are you sure to import this certificate chain into the system? (y/N)



Server certificate is still not activated: First activate your server certificate with custom-domain-activate


Activate the certificate

cf custom-domain-activate ComodoConcileTimeKey --verbose

Command: custom-domain-activate

Organisation:  ConcileTime  (4d641712-8d17-45c6-adca-65c4f61e4202)

API Endpoint:

Default API Server:

Key alias: ComodoConcileTimeKey

Domain Names:

DEBUG:2019/07/30 15:15:18 client.go:81: GET to

DEBUG:2019/07/30 15:15:23 client.go:95: RESPONSE:  [{"guid":"aa316360-c14a-4f9e-8830-ca3662c89f9f","alias":"ComodoConcileTimeKey","subject":"C=US, ST=State, O=ConcileTime, CN=*","dns":["","*"],"chain":"-----BEGIN CERTIFICATE-----\nMIIGBTCCBO2gAwIBAgIRANVR1hWyMasqKrOMc28GWOQwDQYJKoZIhvcNAQELBQAw\ngY8xCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO\nBgNVBAcTB...





DEBUG:2019/07/30 15:15:23 client.go:324: IDENTITY FOUND:  aa316360-c14a-4f9e-8830-ca3662c89f9f

DEBUG:2019/07/30 15:15:23 client.go:100: POST to

DEBUG:2019/07/30 15:15:23 client.go:105: Request: [{  {aa316360-c14a-4f9e-8830-ca3662c89f9f} {} []}]

DEBUG:2019/07/30 15:15:25 client.go:129: HTTP Status: 200

DEBUG:2019/07/30 15:15:25 client.go:130: Response: [{"guid":"fa572e0e-f900-4c49-bf47-61ee3e1f78eb","name":"","state":"inprogress","tlsConfig":{"identityGuid":"aa316360-c14a-4f9e-8830-ca3662c89f9f"},"tlsClientTrustConfig":{}}]


Activating conciletime.comin progress

This operation can take some time. Use custom-domain-list to track the status


Create a CNAME mapping

First, double check that Cloud Foundry understands when to use your custom domain certificate.  Run this cf command and verify that the Domain name with wildcard is listed and activated(in green).
cf custom-domain-list

Command: custom-domain-list

Organisation:  ConcileTime  (4d641712-8d17-45c6-adca-65c4f61e4202)

API Endpoint:

Default API Server:

Activated Certificates: 1

Activated Certificates Quota: 2

Domain Name:

Key:  ComodoConcileTimeKey

Key Status: created, certificate chain uploaded

Certificate Status:  valid

Client Authentication:  disabled

Custom Domain Status:  activated

Domain Name:  *

From an external request mapping standpoint, you need to make sure that requests are all mapped to the Cloud Foundry API endpoint for the landscape where your application is deployed.  Again, I use GoDaddy for DNS management, so I'll illustrate what creating a CNAME mapping looks like.  You may have to enlist your IT department to make CNAME additions to domains your company owns.

Notice that this DNS entry is of type CNAME and the targeted host is the wildcard "*".  Most critically the target of this entry is to the api endpoint of YOUR deployment landscape.  In this case it's us10 with but yours may be eu10(AWS Europe) instead of us10 or otherwise.  This change may take a while to propagate throughout the Internet.  After some time, verify that DNS resolution is correct.  I use the Linux dig utility for this but you might use named or other tool.

$ dig

; <<>> DiG 9.10.6 <<>>

;; global options: +cmd

;; Got answer:

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14920

;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 4, ADDITIONAL: 9


; EDNS: version: 0, flags:; udp: 4096


; IN A


Be sure to try a few other hostnames. You need to be sure ANY domain name maps to the api endpoint.

$ dig

; <<>> DiG 9.10.6 <<>>

;; global options: +cmd

;; Got answer:

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5664

;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 4, ADDITIONAL: 9


; EDNS: version: 0, flags:; udp: 4096


; IN A




Once you're confident external mapping is set and that you're not looking at any cached DNS results and the target is always the api endpoint, you can continue with configuring the internal route mapping.

Map domain to application

Once you have your application deployed into your space, the urls will all point to the domain.  This is the default behavior when deploying.  What you want to do now is to create a new http route to your application so that requests coming in on your custom domain will be forwarded to your application.

Here's what it looks like before adding a route.
cf a

Getting apps in org ConcileTime / space dev as


name             requested state   instances   memory   disk   urls

concile_app_v0   started           1/1         512M     256M

concile_web_v0   started           1/1         512M     256M

concile_utl_v0   started           1/1         512M     256M

concile_srv_v0   started           1/1         512M     256M

concile_db_v0    stopped           0/1         256M     256M


Now let's map a route that will cover all possible hostnames for your domain.  We'll use the asterix here as well as the hostname.  Since the * has meaning on our command line shell we need to put it in single quotes so that the shell doesn't try to expand it.
cf map-route concile_web_v0 --hostname '*'

Creating route * for org ConcileTime / space dev as


Route * is created

Adding route * to app concile_web_v0 in org ConcileTime / space dev as


Now we can check again, this time I'll just check the app-router component of my application.
cf app concile_web_v0

Showing health and status for app concile_web_v0 in org ConcileTime / space dev as

name:              concile_web_v0

requested state:   started

instances:         1/1

usage:             512M x 1 instances

routes:  , *

last uploaded:     Thu 01 Aug 17:23:06 EDT 2019

stack:             cflinuxfs3

buildpack:         nodejs

     state     since                  cpu    memory          disk             details

#0   running   2019-08-01T21:23:57Z   0.0%   47.1M of 512M   104.7M of 256M   

Notice that in routes: * also appears.

We can now browse to, or, or and get the same application.   Again, this is important in order to support multitenant application subscriptions.

You browser should also be completely happy and not show any certificate errors whatsoever.


!Critical configuration!

When your MTA application is deployed, the uaa service instance needs to be passed additional information so that the authentication mechanism can validate the relay destination upon the user's authentication.  This is a kind of whitelist and while you don't have to do this if you're not using custom domains, if you do (like we are here) then it's mandatory.

Maker sure your project's mta.yaml file is configured to pick up an xs-security.json file in your project.


  - name: conciletime-uaa

    type: org.cloudfoundry.managed-service


      path: xs-security.json

      service-name: CONCILETIME_UAA

      service-plan: default

      service: xsuaa


        xsappname: conciletime-${space}

        tenant-mode: dedicated

Now in your xs-security.json file, make sure that you have an oauth2-configuration section.
"oauth2-configuration": {   






Notice that the redirect-uris contains a uri with wildcard matching of the protocol type,  the hostname, and any path that follows.  This is pretty broad matching so you might want to restrict it to known login paths, but it's vital that the hostname wildcard matching be in place in order to support subscriptions of clients as we've discussed above.

Full docs for Application Security Descriptor Configuration Syntax

Philip has put together an extensive collection of videos with all the particulars of building multitenant apps.

Wow, this post got quite long.  If you're still with me, congratulations!  Let me know how your efforts at using custom domains in your mutitenant apps go or leave me a question below.

If I've missed any detail, take a look at this project where I've implemented everything I mention here.


Partners: If you have a question, click here to ask it in the SAP Community . Be sure to tag it with Partnership and leave your company name in the question so that we can better assist you.