Routing in Private Spaces
Last updated December 03, 2024
Table of Contents
- Heroku error codes
- Large cookie & header support
- Response body size logging
- Dyno connection reuse
- Response body buffering
- Maintenance mode & custom error pages
- Content-Length & Content-Type headers
- Query string logging
- SNI servername & host header matching
- SSL security
- HTTP 1.0
- HTTP/2
- Status Line
- Supported HTTP Methods
- Custom DNS Resolvers
The routers in Private Spaces have a slightly different behavior to the routers found in the Common Runtime. This article explains the differences. Please refer to HTTP Routing for an understanding of the shared routing behavior between Common Runtime and Private Spaces.
Heroku error codes
Among the Heroku error codes for the Common Runtime, Private Space routers support the following errors:
- H10 - App crashed
- H11 - Backlog too deep
- H12 - Request timeout
- H13 - Connection closed without response
- H15 - Idle connection
- H17 - Poorly formatted HTTP response
- H18 - Server Request Interrupted
- H19 - Backend connection timeout
- H21 - Backend connection refused
- H25 - HTTP Restriction: Oversized cookies
- H25 - HTTP Restriction: Oversized header
- H25 - HTTP Restriction: Oversized status line
- H26 - Request Error: Unsupported expect header value
- H26 - Request Error: Bad header
- H27 - Client Request Interrupted
- H28 - Client Connection Idle
- H32 - TLS Certificate Mismatch
- H99 - Platform error
Large cookie & header support
Private Space routers support individual HTTP headers up to 512 KB in size.
Response body size logging
Private Space routers count only the size of the response body in the bytes
field of app logs. The Heroku router for Common Runtime counts the status line, headers, and body size.
Dyno connection reuse
For applications that support persistent HTTP connections, Private Space routers might reuse connections to the dyno for multiple requests. These reused connections are independent of the connections between the client software and the Heroku platform.
Response body buffering
Private Space routers might buffer response bodies internally to avoid sending many small body fragments to the client. This improves performance for most applications, but it can have a detrimental effect on applications that require low-latency streaming. Small body fragments are buffered for a maximum of 10ms, but the client might observe larger buffering times due to networking characteristics.
Maintenance mode & custom error pages
These features are not yet available for Fir-generation spaces. Subscribe to our changelog to stay informed of when we add these features.
Both Maintenance Mode and Custom Error Pages are supported in Cedar-generation Private Spaces. Unlike the Common Runtime, however, at least one web dyno must be running for the Private Space routers to serve maintenance and custom error pages.
Content-Length & Content-Type headers
Unlike Common Runtime routing, which allows multiple Content-Length
headers in a request as long as they contain the same value, Private Space routers serve a 400 Bad Response
whenever multiple Content-Length
headers are present.
Private Space routers also attempt to set a Content-Type
header on requests when missing from the dyno’s response based on the MIME Sniffing Standard.
Query string logging
Log messages generated by the Private Spaces router contain query string parameters (also known as URL or GET parameters) in the path
field. Some applications pass sensitive data using the query string. For example, OAuth applications typically use a query string parameter for passing temporary tokens between services.
SNI servername & host header matching
Some clients and CDNs set a different value for the SNI servername than the request’s host header when connecting to a Heroku application. Heroku recommends Private Space applications set up a CNAME record for an application’s public DNS entry that points to the internal space name. This is typically a record for your www.example-app.com
custom domain that points to a desolate-dawn-42.fathomless-ravine-43.herokuspace.com
style record.
Mismatched servername and host header values are allowed, as long as both names are configured as domains for the same application. The desolate-dawn-42.fathomless-ravine-43.herokuspace.com
style domains are configured and managed by Heroku.
Client support for SNI is required to connect to apps in Private Spaces.
SSL security
Apps in Cedar-generation Private Spaces have a choice of cipher suites used to negotiate TLS connections with clients. All new apps are created using the spaces-tls-salesforce
suite, which only supports TLS v1.2 and 1.3. Fir-generation spaces only supports spaces-tls-salesforce
.
Available Private Space Cipher Suites
Fir-generation spaces only supports spaces-tls-salesforce
default ciphers. Setting cipher feature flags have no effect in Fir.
The spaces-tls-legacy
and spaces-strict-tls
ciphers reached end-of-life in April 2023. It’s recommended to configure your apps in Private Spaces with only spaces-tls-salesforce
or spaces-tls-modern
for security best practices.
You can configure apps in Private Spaces with one or more of the following cipher suites.
spaces-tls-salesforce
Complies with Salesforce TLS Guidelines and used on all new apps.spaces-tls-modern
The modern suite supports only TLSv1.2 and TLSv1.3. It provides excellent security and works with relatively new browsers and mobile/IoT clients.
TLSv1.3 Cipher Suites
Cipher suite selection works differently for TLSv1.3 and cipher suite settings described in this section only apply to pre-TLSv1.3 TLS versions. Modifying cipher-suites for TLSv1.3 is not possible and the following default cipher suites are supported:
TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
Salesforce Cipher Suite
The Salesforce suite is standard on all new apps and offers an easy way to ensure your app is using the Salesforce TLS Guidelines. Please note our current configuration does not support the TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
nor TLS_RSA_WITH_AES_256_CBC_SHA256
cipher suites.
Ciphers
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
Modern Cipher Suite
The modern suite supports only TLSv1.2. It provides excellent security and works with relatively new browsers and mobile/IoT clients. To apply this suite, disable other suites and enable spaces-tls-modern
suite as shown.
$ heroku features:disable spaces-tls-salesforce --app desolate-dawn-42
$ heroku features:enable spaces-tls-modern --app desolate-dawn-42
$ heroku features:disable spaces-tls-legacy --app desolate-dawn-42
$ heroku features:disable spaces-strict-tls --app desolate-dawn-42
Ciphers
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Default Ciphers
The default suite supports TLSv1.2 and TLSv1.3. It provides good security and is compatible with a large range of browsers and clients. To get the default TLS behavior, disable all other TLS cipher suite features as shown.
Default cipher suites are the ciphers that remain after all other suites are disabled. New apps are created with the spaces-tls-salesforce
feature enabled.
$ heroku features:disable spaces-tls-salesforce --app desolate-dawn-42
$ heroku features:disable spaces-tls-modern --app desolate-dawn-42
$ heroku features:disable spaces-tls-legacy --app desolate-dawn-42
$ heroku features:disable spaces-strict-tls --app desolate-dawn-42
Ciphers
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
[Deprecated] Strict
With the spaces-strict-tls
feature flag enabled, the Private Spaces routers supports TLS versions 1.1 and 1.2. This flag is deprecated and should only be used for backwards compatibility with previous Heroku TLS termination behavior.
$ heroku features:disable spaces-tls-salesforce --app desolate-dawn-42
$ heroku features:disable spaces-tls-modern --app desolate-dawn-42
$ heroku features:disable spaces-tls-legacy --app desolate-dawn-42
$ heroku features:enable spaces-strict-tls --app desolate-dawn-42
Ciphers
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
HTTP 1.0
Private Space routers convert HTTP 1.0 into HTTP 1.1 requests that are forwarded to dynos. HTTP 1.1 responses from dynos are sent to the client as HTTP 1.0 responses if the original request used HTTP 1.0.
Common Runtime routers convert HTTP 1.0 requests to HTTP 1.1 requests, but do not convert HTTP 1.1 responses back to HTTP 1.0 responses.
HTTP/2
Considerations
- A valid TLS certificate is required. We recommend using Heroku ACM.
- HTTP/2 terminates at the Heroku router and we forward HTTP/1.1 from the router to your app.
Private and Shield Private Spaces customers can use either their Heroku default domain or their custom domain to handle HTTP/2 traffic.
Enable and Disable HTTP/2 for Apps in Spaces
You can’t disable HTTP/2 on Fir-generation apps. HTTP/2 is always on.
To enable HTTP/2, run the command:
$ heroku features:enable spaces-http2 -a <app name>
You can verify your app is receiving HTTP/2 requests by referencing the protocol
value in your Heroku Router Logs like this example:
2024-04-26T16:58:32.943253+00:00 heroku[router]: at=info method=GET path="/" host=my-app.example.com request_id=6903a168-b79b-ec27-03c8-b8f64d8d8792 fwd=138.68.186.89 dyno=web.1 connect=0ms service=0ms status=200 bytes=0 protocol=http2.0 tls_version=tls1.3
To disable HTTP/2, run the command:
$ heroku features:disable spaces-http2 -a <app name>
Status Line
Private Space routers treat the entire first line of the request (up to the first \n
character) as the status line, regardless of the line ending in a CRLF
(\r\n
). It is typical for HTTP servers like Nginx to allow bare newlines in the end of the status line.
Supported HTTP Methods
Private Space routers supports any HTTP method (sometimes called a “verb”), even those not defined in an RFC.
Custom DNS Resolvers
Custom DNS resolvers are unavailable in Fir-generation spaces.
Private Space apps support injecting a single DNS Resolver as the dynos first DNS server target, followed by the standard Private Space DNS target. To use this feature you need to enable the spaces-extra-resolver
flag on the desired apps and then configure the HEROKU_EXTRA_RESOLVER
config var.
Example:
$ heroku labs:enable spaces-extra-resolver -a "$APP_NAME"
$ heroku config:set -a "$APP_NAME" HEROKU_EXTRA_RESOLVER=DNS-Server-IP