Skip to Content
Technical Articles

Step-By-Step Guide to Custom Domains with Multitenant Multi-Target Applications

While there are several other great posts for configuring custom domains in cloud foundry,

Demystifying SAP Cloud Platform Custom Domains

No Pain, No Gain. Get Started with 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(conciletime.com).  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

www.conciletime.com = Main web entry point for static content.

conciletime.conciletime.com = 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 domain.com name, but doesn’t have to be)

client1.conciletime.com = 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.

ct-client2.conciletime.com = 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 *.conciletime.com 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 conciletime.com
Creating domain conciletime.com for org ConcileTime as andrew.lunde@sap.com...

OK
Check that your domain got created properly.
cf domains
Getting domains in org ConcileTime as andrew.lunde@sap.com...

name                               status type

cfapps.us10.hana.ondemand.com       shared

cert.cfapps.us10.hana.ondemand.com  shared

apps.internal                       shared

conciletime.com                     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=*.conciletime.com”  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=*.conciletime.com" conciletime.com --verbose
Command: custom-domain-create-key

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

API Endpoint:  https://api.cf.us10.hana.ondemand.com

Default API Server:  https://custom-domain-certificates-api.cf.us10.hana.ondemand.com

Key:ComodoConcileTimeKey

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

Domain Names: 

Host Names:  conciletime.com

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

y

DEBUG:2019/07/30 14:22:07 client.go:100: POST to https://custom-domain-certificates-api.cf.us10.hana.ondemand.com/api/v1/organizations/4d641712-8d17-45c6-adca-65c4f61e4202/identities

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

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=*.conciletime.com","dns":["conciletime.com"]}]

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:  https://api.cf.us10.hana.ondemand.com

Default API Server:  https://custom-domain-certificates-api.cf.us10.hana.ondemand.com

—–BEGIN CERTIFICATE REQUEST—–

MIIC1DCCAbwCAQAwTzELMAkGA1UEBhMCVVMxDjAMBgNVBAgTBVN0YXRlMRQwEgYD

VQQKEwtDb25jaWxlVGltZTEaMBgGA1UEAwwRKi5jb25jaWxldGltZS5jb20wggEi

UrrQ4Wo0y3VW41u4o7YGSVJlWQ5GNxQOVbfdlzLJoLCIpb7nQgWb0NnWhC0ap5Qb

n8BbI37SEow=

—–END CERTIFICATE REQUEST—–

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. sapcloud.conciletime.com) 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. *.*.conciletime.com) 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

https://comodosslstore.com

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 _0A75XXXXXXXXXXXXXXXXXXB2E2932182.conciletime.com
; <<>> DiG 9.10.6 <<>> _0A75XXXXXXXXXXXXXXXXXXB2E2932182.conciletime.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 28823
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;_0A75XXXXXXXXXXXXXXXXXXB2E2932182.conciletime.com. IN A
;; ANSWER SECTION:
_0A75XXXXXXXXXXXXXXXXXXB2E2932182.conciletime.com. 1800 IN CNAME xxxxx8fca937722e2ac4165f165fbcd0.xxxxx620f65fc3a390f19560c9816f30.xxxxxptoo9pw50e59ka5.comodoca.com.
;; AUTHORITY SECTION:
comodoca.com. 600 IN SOA ns1.as48447.net. hostmaster.comodoca.com. 2019070802 1800 1200 1814400 5400
;; Query time: 117 msec
;; SERVER: 192.168.1.254#53(192.168.1.254)
;; 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 <noreply@notifications.sectigo.com>

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

To: “Lunde, Andrew” <andrew.lunde@sap.com>

Subject: ORDER #25500XXXX – Your PositiveSSL Wildcard Certificate for *.conciletime.com

 

Your PositiveSSL Wildcard Certificate for *.conciletime.com is attached!

Dear andrew.lunde@sap.com,

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

To help reduce domain name mismatch warnings, we have also included the domain name conciletime.com 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 *.conciletime.com 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 *.conciletime.com in text format (if required):

—–BEGIN CERTIFICATE—–

MIIGBzCCBO+gAwIBAgIRAOu8RmSkyiweALyVCVENPugwDQYJKoZIhvcNAQELBQAw

gY8xCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO

 

EarDqD2umMD244ohsoWTgnJdj3F5nl03TzU/QOVXfB8ESQyDoNgvppOO052Nxbo4

viaxq3C4zkNZH5o=

—–END CERTIFICATE—–

 

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:  https://api.cf.us10.hana.ondemand.com

Default API Server:  https://custom-domain-certificates-api.cf.us10.hana.ondemand.com

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

Validity:valid

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

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

-----BEGIN CERTIFICATE-----

MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU

MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs

...

6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC

Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX

c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a

mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=

-----END CERTIFICATE-----

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

Validity:valid

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

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

-----BEGIN CERTIFICATE-----

MIIFdzCCBF+gAwIBAgIQE+oocFv07O0MNmMJgGFDNjANBgkqhkiG9w0BAQwFADBv

MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk

ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF

...

lQ9ew4IcH9Z35zyKwKoJ8OkLJvHgwmp1ocd5yblSYMgpEg7wrQPWCcR23+WmgZWn

RtqCV6mVksW2jwMibDN3wXsyF24HzloUQToFJBv2FAY7qCUkDrvMKnXduXBBP3zQ

YzYhBx9G/2CkkeFnvN4ffhkUyWNnkepnB2u0j4vAbkN9w6GAbLIevFOFfdyQoaS8

Le9Gclc1Bb+7RrtubTeZtv8jkpHGbkD4jylW6l/VXxRTrPBPYer3IsynVgviuDQf

Jtl7GQVoP7o81DgGotPmjw7jtHFtQELFhLRAlSv0ZaBIefYdgWOWnU914Ph85I6p

0fKtirOMxyHNwu8=

-----END CERTIFICATE-----

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

Validity:valid

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

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

-----BEGIN CERTIFICATE-----

MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB

iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl

cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV

...

LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5

yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K

00u/I5sUKUErmgQfky3xxzlIPK1aEn8=

-----END CERTIFICATE-----

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

Subject Alternative Names:

  DNSName: *.conciletime.com

  DNSName: conciletime.com

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

Validity:valid

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

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

-----BEGIN CERTIFICATE-----

MIIGBTCCBO2gAwIBAgIRANVR1hWyMasqKrOMc28GWOQwDQYJKoZIhvcNAQELBQAw

gY8xCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO

BgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDE3MDUGA1UE

...

wwMFLeAxS6MYivKclw3oOz2GU3n1IK2cXlTeC6JO+zsl5l4l1AUYz4ykNKihnW+n

IHnmckbC1GIAfN19OvaIE/CssI7VNdZQ4fGc3WKNDcYjseVEZpDaigMPTxDt8vIt

DvzjLzuyws2zlLzw0oeJuml1YqC2MKo1u2wTlVhQMrd3rTQWi9GQhfJypqXac0Zm

diGqTzgO96vxZwIHsYXQMLz5Eps7Yo8rLcfNnCxYzNhQM4rvCqRkg6klvOgmncue

z6iP+ouzZAYm

-----END CERTIFICATE-----

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

y

OK

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

 

Activate the certificate

cf custom-domain-activate ComodoConcileTimeKey conciletime.com --verbose
Command: custom-domain-activate

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

API Endpoint:  https://api.cf.us10.hana.ondemand.com

Default API Server:  https://custom-domain-certificates-api.cf.us10.hana.ondemand.com

Key alias: ComodoConcileTimeKey

Domain Names: conciletime.com

DEBUG:2019/07/30 15:15:18 client.go:81: GET to  https://custom-domain-certificates-api.cf.us10.hana.ondemand.com/api/v1/organizations/4d641712-8d17-45c6-adca-65c4f61e4202/identities/ComodoConcileTimeKey

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=*.conciletime.com","dns":["conciletime.com","*.conciletime.com"],"chain":"-----BEGIN CERTIFICATE-----\nMIIGBTCCBO2gAwIBAgIRANVR1hWyMasqKrOMc28GWOQwDQYJKoZIhvcNAQELBQAw\ngY8xCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO\nBgNVBAcTB...

c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a

mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=

-----END CERTIFICATE-----

}]

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 https://custom-domain-certificates-api.cf.us10.hana.ondemand.com/api/v1/organizations/4d641712-8d17-45c6-adca-65c4f61e4202/serverNames

DEBUG:2019/07/30 15:15:23 client.go:105: Request: [{ conciletime.com  {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":"conciletime.com","state":"inprogress","tlsConfig":{"identityGuid":"aa316360-c14a-4f9e-8830-ca3662c89f9f"},"tlsClientTrustConfig":{}}]

OK

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:  https://api.cf.us10.hana.ondemand.com

Default API Server:  https://custom-domain-certificates-api.cf.us10.hana.ondemand.com

Activated Certificates: 1

Activated Certificates Quota: 2

Domain Name:    conciletime.com


Key:     ComodoConcileTimeKey

Key Status:   created, certificate chain uploaded

Certificate Status:   valid

Client Authentication:   disabled

Custom Domain Status:   activated

Domain Name:    *.conciletime.com

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 api.cf.us10.hana.ondemand.com 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 www.conciletime.com
$ dig www.conciletime.com

; <<>> DiG 9.10.6 <<>> www.conciletime.com

;; global options: +cmd

;; Got answer:

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

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

;; OPT PSEUDOSECTION:

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

;; QUESTION SECTION:

;www.conciletime.com. IN A

;; ANSWER SECTION:

www.conciletime.com. 3600 IN CNAME api.cf.us10.hana.ondemand.com.

api.cf.us10.hana.ondemand.com. 9915 IN CNAME cf-proxy-hcp-live-us10-2030508056.us-east-1.elb.amazonaws.com.

cf-proxy-hcp-live-us10-2030508056.us-east-1.elb.amazonaws.com. 6 IN A 54.209.228.56

cf-proxy-hcp-live-us10-2030508056.us-east-1.elb.amazonaws.com. 6 IN A 52.7.38.158

cf-proxy-hcp-live-us10-2030508056.us-east-1.elb.amazonaws.com. 6 IN A 52.4.61.78

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

dig abc.conciletime.com
$ dig abc.conciletime.com

; <<>> DiG 9.10.6 <<>> abc.conciletime.com

;; global options: +cmd

;; Got answer:

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

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

;; OPT PSEUDOSECTION:

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

;; QUESTION SECTION:

;abc.conciletime.com. IN A

;; ANSWER SECTION:

abc.conciletime.com. 3600 IN CNAME api.cf.us10.hana.ondemand.com.
dig whatever-hostname.conciletime.com


;; ANSWER SECTION:

whatever-hostname.conciletime.com. 3600 IN CNAME api.cf.us10.hana.ondemand.com.

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 hana.ondemand.com 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 andrew.lunde@sap.com...

OK

name             requested state   instances   memory   disk   urls

concile_app_v0   started           1/1         512M     256M   conciletime-app.cfapps.us10.hana.ondemand.com

concile_web_v0   started           1/1         512M     256M   conciletime.cfapps.us10.hana.ondemand.com

concile_utl_v0   started           1/1         512M     256M   conciletime-utl.cfapps.us10.hana.ondemand.com

concile_srv_v0   started           1/1         512M     256M   conciletime-srv.cfapps.us10.hana.ondemand.com

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 conciletime.com --hostname '*'
Creating route *.conciletime.com for org ConcileTime / space dev as andrew.lunde@sap.com...

OK

Route *.conciletime.com is created

Adding route *.conciletime.com to app concile_web_v0 in org ConcileTime / space dev as andrew.lunde@sap.com...

OK

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 andrew.lunde@sap.com...

name:              concile_web_v0

requested state:   started

instances:         1/1

usage:             512M x 1 instances

routes:            conciletime.cfapps.us10.hana.ondemand.com, *.conciletime.com

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: *.conciletime.com also appears.

We can now browse to www.conciletime.com, or abc.conciletime.com, or xyz.conciletime.com 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.

resources:

...

  - name: conciletime-uaa

    type: org.cloudfoundry.managed-service

    parameters:

      path: xs-security.json

      service-name: CONCILETIME_UAA

      service-plan: default

      service: xsuaa

      config:

        xsappname: conciletime-${space}

        tenant-mode: dedicated

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

"oauth2-configuration": {   

"redirect-uris":

[

"http*://*.conciletime.com/**"

]   

}

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.  https://www.youtube.com/playlist?list=PLkzo92owKnVx3Sh0nemX8GoSNzJGfsWJM

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.

https://github.com/alundesap/conciletime/tree/post01

-Andrew

2 Comments
You must be Logged on to comment or reply to a post.
  • Great stuff Andrew … didn’t even realize that custom domains where possible on CF .. sounds logical if you think about it … thanks for laying out all the details 🙂

  • Excellent post Andrew, wanted to do something similar for our internal wiki. One question: do you know maybe if it is possible to export custom domain certificate and private key from SAP Cloud platform to place it on some other host (I understand possible security issues)?

    Thanks