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
      • Working with the Play Framework
      • Working with Spring Boot
      • Java Advanced Topics
    • 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
  • Preparing a Java Web App for Production on Heroku

Preparing a Java Web App for Production on Heroku

English — 日本語に切り替える

Last updated December 16, 2021

Table of Contents

  • Force the use of HTTPS
  • Rate-limit API calls
  • 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

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 important steps required to make a Java web application production-ready on Heroku. If you are using Spring Boot, you might prefer the article on Preparing a Spring Boot App for Production.

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 (of 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 creating a Servlet filter in your app with the following code:

public class HttpsEnforcer implements Filter {
  public static final String X_FORWARDED_PROTO = "X-Forwarded-Proto";

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {}

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    HttpServletResponse response = (HttpServletResponse) servletResponse;

    if (request.getHeader(X_FORWARDED_PROTO) != null) {
      if (request.getHeader(X_FORWARDED_PROTO).indexOf("https") != 0) {
        String pathInfo = (request.getPathInfo() != null) ? request.getPathInfo() : "";
        response.sendRedirect("https://" + request.getServerName() + pathInfo);
        return;
      }
    }

    filterChain.doFilter(request, response);
  }

  @Override
  public void destroy() { }
}

This configuration instructs the servlet container 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.

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 by creating another Servlet filter in your application. First, add the following dependency to your pom.xml:

<dependency>
    <groupId>com.github.vladimir-bukhtoyarov</groupId>
    <artifactId>bucket4j-core</artifactId>
</dependency>

The create a Servlet filter with the following code:

public class ThrottlingFilter implements javax.servlet.Filter {

    private Bucket createNewBucket() {
         long overdraft = 50;
         Refill refill = Refill.greedy(10, Duration.ofSeconds(1));
         Bandwidth limit = Bandwidth.classic(overdraft, refill);
         return Bucket4j.builder().addLimit(limit).build();
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpSession session = httpRequest.getSession(true);

        String appKey = SecurityUtils.getThirdPartyAppKey();
        Bucket bucket = (Bucket) session.getAttribute("throttler-" + appKey);
        if (bucket == null) {
            Bucket bucket = createNewBucket();
            session.setAttribute("throttler-" + appKey, bucket);
        }

        if (bucket.tryConsume(1)) {
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
            httpResponse.setContentType("text/plain");
            httpResponse.setStatus(429);
            httpResponse.getWriter().append("Too many requests");
        }
    }

}

Other examples can be found in the Bucket4j documentation.

Use a distributed session store

Storing sessions in-memory inhibits the disposability and horizontal scalability of dynos. That’s why it’s important to instead use a distributed session store like Redis.

There are many ways to implement session storage with Java and Redis that depend on your server and frameworks. Heroku recommends using Redisson, which works with most popular options, as described in this 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, the app should:

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

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

Configure error and maintenance pages

Heroku lets you configure 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 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 Papertrail in action, visit your application’s Heroku URL a few times. Each visit generates more log messages, which should be routed to the 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 scans your source code and compares the dependencies in either your pom.xml or build.gradle file against its database of known security vulnerabilities. If it finds any, it sends a notification that describes how to resolve them.

Keep reading

  • Java

Feedback

Log in to submit feedback.

Setting the HTTP Port for Java Applications Setting the HTTP Port for Java Applications

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