Skip Navigation
Show nav
Heroku Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
  • Documentation
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
View categories

Categories

  • Heroku Architecture
    • Dynos (app containers)
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Command Line
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery
    • Continuous Integration
  • Language Support
    • Node.js
    • Ruby
      • Working with Bundler
      • Rails Support
    • Python
      • Background Jobs in Python
      • Working with Django
    • Java
      • Working with Maven
      • Java Database Operations
      • Java Advanced Topics
      • Working with Spring Boot
    • PHP
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Getting Started
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
    • Heroku Data For Redis
    • Apache Kafka on Heroku
    • Other Data Stores
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
    • Compliance
  • Heroku Enterprise
    • Private Spaces
      • Infrastructure Networking
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
    • Single Sign-on (SSO)
  • Patterns & Best Practices
  • Extending Heroku
    • Platform API
    • App Webhooks
    • Heroku Labs
    • Building Add-ons
      • Add-on Development Tasks
      • Add-on APIs
      • Add-on Guidelines & Requirements
    • Building CLI Plugins
    • Developing Buildpacks
    • Dev Center
  • Accounts & Billing
  • Troubleshooting & Support
  • Integrating with Salesforce
  • Language Support
  • Java
  • Working with Spring Boot
  • Preparing a Spring Boot App for Production on Heroku

Preparing a Spring Boot App for Production on Heroku

English — 日本語に切り替える

Last updated November 29, 2021

Table of Contents

  • Force the use of HTTPS
  • Rate-limit API calls
  • Use structured logging
  • Use UUIDs for all Postgres Primary Keys
  • Remove secrets from source code
  • Use a distributed session store
  • Enable JVM Runtime Metrics
  • Configure alerting
  • Configure error and maintenance pages
  • Attach a logging add-on
  • Attach an error tracking add-on
  • Attach a vulnerability detection add-on
  • Further Reading

It is important to ensure that an app is secure, scalable, and resilient to failure before sending it to production. This guide provides an overview of many common and important steps required to make a Spring Boot app production-ready on Heroku.

Force the use of HTTPS

Unless you have very specific needs, your app should be using HTTPS for all requests. Heroku provides an HTTPS URL (in the form https://<app-name>.herokuapp.com) for every app, as well as free tools for adding your own domains and certificates.

You can enforce the use of HTTPS when your app is running on Heroku by adding the following configuration to your Spring Boot app.

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.requiresChannel()
      .requestMatchers(r -> r.getHeader("X-Forwarded-Proto") != null)
      .requiresSecure();
  }
}

If you already have a WebSecurityConfigurerAdapter implementation, then add the above configuration to it.

This configuration tells Spring to redirect all plain HTTP requests back to the same URL using HTTPS if the X-Forwarded-Proto header is present. Heroku sets the X-Forwarded-Proto header for you, which means the request will be redirected back through the Heroku router where SSL is terminated. In your localhost environment, you can continue to use plain HTTP.

For more information see the official Spring Boot docs on how to Enable HTTPS When Running behind a Proxy Server.

Rate-limit API calls

Rate limiting is the process of controlling traffic to a server based on client IPs, blocked IPs, geolocation, and other factors. One of the most popular rate-limiting libraries for Java is Bucket4j, which can be used with Spring Boot via the Spring Boot Starter for Bucket4j.

After adding the dependency and configuring a back-end, some minimal configuration might look like this in your application.yml:

bucket4j:
  enabled: true
  filters:
  - cache-name: buckets
    url: /*
    rate-limits:
    - bandwidths:
      - capacity: 5
        time: 10
        unit: seconds

This configuration limits an individual user to a maximum of 5 requests within a 10 second period.

Use structured logging

Structured logging makes it easier to search and perform analytic operations on logging data. You can use Logback to encode your Spring Boot logs into JSON format by adding the following dependency to your app:

<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
</dependency>

Then create a logback.xml configuration file in the src/main/resources directory with the following contents:

<configuration>
    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
    </appender>
    <logger name="jsonLogger" additivity="false" level="DEBUG">
        <appender-ref ref="consoleAppender"/>
    </logger>
    <root level="INFO">
        <appender-ref ref="consoleAppender"/>
    </root>
</configuration>

The result will be log lines that look like this:

{"@timestamp":"2018-04-16T09:36:34.641-05:00","@version":"1","message":"Started Main in 4.154 seconds (JVM running for 4.832)","logger_name":"com.example.Main","thread_name":"restartedMain","level":"INFO","level_value":20000}

JSON formatted logs may be more difficult to read when using the heroku logs command, but they are far easier to search in a real production environment. Thus, you may choose to retain a human-readable log format in non-production environments.

Use UUIDs for all Postgres Primary Keys

By default, Spring Data will use integers for primary keys in a Postgres database. However, this can leave your app vulnerable to exploits were attackers guess the next record identifier. It is preferable to use UUID primary keys, which cannot be guessed or enumerate. To configure your Spring Data models with UUID primary keys, use the @GeneratedValue annotation in conjunction with the java.util.UUID type like this:

@Entity
class MyModel {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private UUID id;
}

In this way, a random UUID is assigned when the model is created. Then add a UUID AttributeConverter to your app like this:

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.util.UUID;

@Converter(autoApply = true)
public class UUIDConverter implements AttributeConverter<UUID, UUID> {
    @Override
    public UUID convertToDatabaseColumn(UUID attribute) {
        return attribute;
    }
    @Override
    public UUID convertToEntityAttribute(UUID dbData) {
        return dbData;
    }
}

UUIDs can be freely exposed without disclosing sensitive information. They are also unpredictable, perform well, and do not suffer from integer rollover.

Remove secrets from source code

It is unsafe to keep sensitive information in source code (i.e. checked into Git). Source code is stored in clear-text and is not encrypted on the server. Furthermore, storing secrets in source code increases the risk of accidentally connecting to a production service from a staging or test service.

All sensitive data (such as passwords, API tokens, and private keys) should be stored as configuration variables using the heroku config command. You can then access using environment variable substitution in your application.yml like this:

admin:
  password: ${ADMIN_PASSWORD}

Note that most relational database URLs require zero-configuration on Heroku when used with Spring.

Use a distributed session store

Storing sessions in-memory prohibits disposability and horizontal scalability of dynos. That’s why it’s important to use a distributed session store like Redis. Spring Boot has multiple mechanisms for storing sessions in Redis, including the Spring Session module for Redis. However, Heroku recommends using Redisson as described in our article on Java Session Handling.

Enable JVM Runtime Metrics

The JVM Runtime Metrics feature allows you to view heap memory, non-heap memory, and garbage collection activity for any app that runs inside of the Java Virtual Machine (JVM). The feature is safe to use in production, and can help you identify performance related problems.

Configure alerting

When your application experiences a problem, it should alert a human. At a minimum, it should:

  • Alert a human if it is down
  • Alert a human if error rates go above specific thresholds
  • Alert a human if latency is high

Heroku’s Threshold Alerting feature is available to apps running on Professional dynos. But you can also choose from the many Alerting and Monitoring add-ons in the Heroku Add-on Marketplace.

Configure error and maintenance pages

Heroku provides a mechanism for configuring the static HTML pages that are shown to users when your application experiences an error (such as crashing) or goes down for maintenance. Please see the Dev Center guide to Customizing Error Pages for more information.

Attach a logging add-on

By default, Heroku stores 1500 lines of logs from your application. However, it makes the full log stream available as a service that several add-on providers consume to provide features such as log persistence, search, and alerts via email or SMS.

You can provision one of these logging add-ons, Papertrail, by running the following command on your app:

$ heroku addons:create papertrail

To see this particular add-on in action, visit your application’s Heroku URL a few times. Each visit will generate more log messages, which should now get routed to the papertrail add-on.

Attach an error tracking add-on

While your application logs capture the regular activity of your server processes, an error tracking add-on can capture more detail for exceptional cases. This can be useful in identifying common problems your users encounter, or to diagnose poor performance. The Add-on Marketplace has a number of options including the Rollbar service, which you can add to your app by running:

$ heroku addons:create rollbar

After following the guide for setting up Rollbar integration, you’ll begin to see a record of all errors with their associated stack traces and other details coming from your app.

Attach a vulnerability detection add-on

The final add-on every production app should use is one that detects security vulnerabilities in your source code. One such service is Snyk, which you can attach to your app by running:

$ heroku addons:create snyk

Snyk will scan your source code, and compare the dependencies in either your pom.xml or build.gradle against its database of known security vulnerabilities. If it finds any it will send a notification telling you how to update it.

Further Reading

For more information and guidance on running Spring Boot apps in production, please see the official Spring documentation on Moving to Production

Keep reading

  • Working with Spring Boot

Feedback

Log in to submit feedback.

Scaling a Spring Boot Application with Memcache Scaling a Spring Boot Application with Memcache

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Podcasts
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing

Subscribe to our monthly newsletter

Your email address:

  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Heroku Podcasts
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Facebook
  • Instagram
  • Github
  • LinkedIn
  • YouTube
Heroku is acompany

 © Salesforce.com

  • heroku.com
  • Terms of Service
  • Privacy
  • Cookies
  • Cookie Preferences