DevOps

Setting Up Reverse Proxy in Heroku Using Nginx

Dario Djuric
5 min read
Setting Up Reverse Proxy in Heroku Using Nginx
This article was written over 18 months ago and may contain information that is out of date. Some content may still be relevant, but please refer to official documentation for the latest information.

Nowadays, nginx is probably the most popular web server used for web apps. It's lightweight, fast, and easy to configure. It's not always necessarily used as a web server though. Given that many frameworks today come with a built-in web server, nginx is sometimes used in front as a reverse proxy and/or a load balancer. In this blog post, we will show you how to deploy nginx as a reverse proxy on Heroku.

What Is a Reverse Proxy?

While a forward proxy, often called simply a proxy, sits in front of a group of clients and has the purpose of "hiding" those clients from the rest of the Internet, a reverse proxy sits in front of web servers and "hides" them from clients accessing them. From a client's perspective, the client is unaware that they are accessing a backend web server - they are only aware of the reverse proxy.

The below image shows both types of proxies and where they are placed:

CleanShot 2022-10-18 at 18.58.13@2x

Implementing a Reverse Proxy in Heroku

When it comes to setting up a reverse proxy in Heroku, the recommended way is to set it up using nginx. You might want to do this, for example, if you want to short-circuit an app and forward to somewhere else, or if you are not happy with the capabilities of the app's web server and want something more advanced. In either case, nginx is an excellent choice.

There are two options for setting up an nginx-based reverse proxy in Heroku- both of which we'll cover as part of this blog post. Picking the one to use depends on the type of the stack allocated to your Heroku app. Heroku supports either Ubuntu-based stacks (non-container), which allow you to use buildpacks to customize the build of your app, or container-based stacks, where you are responsible for building and deploying your app via Docker. Buildpacks execute before the app is started, and are typically used to install the required dependencies (such as Ruby or Node).

Let's start with the option that is more suitable for container stacks:

Dockerized nginx

In this solution, a Docker container is responsible for running nginx. You build the Docker image locally, and then push it to Heroku's Docker registry after which it can be used in the app.

CleanShot 2022-10-20 at 17.17.48@2x

To show you how to set it up, let's first create a Heroku app from scratch:

heroku apps:create heroku-nginx-reverse-proxy	

Create the nginx config template file and name it nginx.conf.template:

server {
    # https://github.com/docker-library/docs/tree/master/nginx#using-environment-variables-in-nginx-configuration-new-in-119
    listen ${PORT};

    error_log stderr;
    access_log /dev/stdout;

    location / {
        proxy_pass https://www.google.com/;
    }
}

The reason why the configuration is suffixed with .template is that this is actually a template configuration that will be parsed by a function inside the Docker image. This is a special feature of the Docker image that has been added recently, and allows you to inject values of environment variables into your templates. This is absolutely necessary in Heroku because any web server running in Heroku must listen on the port provided by the PORT environment variable. This means the port nginx is listening on must be determined in runtime, not hardcoded in the configuration.

Next, create the Dockerfile with the following contents:

FROM nginx
COPY nginx.conf.template /etc/nginx/templates/default.conf.template

Build the Docker image using the following command:

heroku container:push web

Then push it up it so that it is used by the app:

heroku container:release web

That's it. If you now run heroku open you should see your Heroku app reverse-proxying to Google.

nginx Buildpack

This solution is the best fit for non-container apps. Normally, buildpacks are used to install the dependencies of your app. But in this case, the nginx buildpack allows overriding your app's web server. In the nginx buildpack, you can run nginx either in solo mode (if you want to run only nginx, without the web server) or in a non-solo mode where nginx runs alongside your web server.

In our example, we are running it in solo mode, effectively short-circuiting our app.

CleanShot 2022-10-20 at 17.18.53@2x

In an existing Heroku app, under the Settings page, add a new buildpack using the following URL:

https://github.com/heroku/heroku-buildpack-nginx.git

CleanShot 2022-10-19 at 22.58.44@2x

In your repository, create a new Procfile with the following URL:

web: bin/start-nginx-solo

The nginx buildpack expects the nginx config to be in config/nginx.conf.erb. This is a template file in the Dockerized nginx option, but this time Ruby syntax is used (ERB stands for Embedded RuBy). Create that file and insert the following content:

daemon off;
# Heroku dynos have at least 4 cores.
worker_processes <%= ENV['NGINX_WORKERS'] || 4 %>;

events {
    use epoll;
    accept_mutex on;
    worker_connections <%= ENV['NGINX_WORKER_CONNECTIONS'] || 1024 %>;
}

http {
    log_format l2met 'measure#nginx.service=$request_time request_id=$http_x_request_id';
    access_log <%= ENV['NGINX_ACCESS_LOG_PATH'] || 'logs/nginx/access.log' %> l2met;
    error_log <%= ENV['NGINX_ERROR_LOG_PATH'] || 'logs/nginx/error.log' %>;

    server {
        listen <%= ENV["PORT"] %>;

	    location / {
	        proxy_pass https://www.google.com/;
	    }
    }
}

As you can see, again we need to pass in at least the PORT environment variable which is provided to the app on runtime. Other environment variables are optional and they default to sane values if they are not provided.

Now Git push to Heroku's remote and the buildpack will be in effect. You can verify this by typing heroku open in the shell.

Conclusion

Reverse proxies can be very useful in scenarios where you want a fast, non-blocking web server such as nginx doing the heavy lifting of communicating with the clients. Heroku is very flexible in deploying nginx as we've seen in this blog post. You have two very good options for deployment, depending on your requirements and the needs of your app.

As always, you can find the source code of our examples in our GitHub repository.

About the author

Dario Djuric

Dario Djuric

Senior Software Engineer

Dario is a full-stack engineer who has spent most of his career doing enterprise Java projects. He has always had a hidden passion for frontend, though -- and he is now able to pursue that passion at This Dot. He spends most of his free time with his two sons, but occasionally, he manages to squeeze in some casual sports activities such as jogging, cycling, and soccer.

Keep reading

View all posts →

Double Click: Jump on the waitlist for Fig.io's new autocomplete terminal add-on!

Welcome to the Double Click! This is the weekly blog series that shines a spotlight on emerging technologies, technological concepts, and community projects that enrich the JavaScript Ecosystem! This week, I’m sharing a really cool, new tool for your existing terminal that I LOVE: Fig! This add on provides VSCode style autocomplete, and is currently being made available for free to those who sign up on their website. When using the Fig add on, you get autocomplete options in your terminal, showing you everything you need, such as lists of available directories, folders, git commands, branches, components, and more without taking you out of your flow. How magical is it to get more time to focus on your code rather than trying to remember shortcuts and commands in terminal? (LIFESAVER!) Fig is also built to integrate with a number of CLI tools, including npm, Heroku, AWS, GCP, Docker, and more, with plans to add further integrations as the technology develops and new users start including Fig in their tool belt. Other features of this add on include keyboard first functionality, allowing developers to quickly use the auto completes without having to touch their mouse, open source completion specs, which ensure that the Fig add on always remains up to date and relevant for users, and the add on runs locally, offering speed and security. I’m already using Fig, and am a huge supporter of any tools that work to remove complexities from my development process. I am excited to see this project grow!...

Tracy Lee1 min
ToolingHerokuJavaScriptnpm

Deploying Nx workspace based Angular and NestJS apps to Heroku

Deploying Angular and NestJS apps to Heroku in an Nx workspace In previous articles, I've shown you how to create an Nx Workspace with Angular and NestJS applications in it. After the applications are ready, we need to host them somewhere. Heroku is one of the services that lets us deploy applications easily. In this article, I'll demonstrate how to deploy the Angular and NestJS applications that are developed using an Nx monorepo. You can find the example code with the aforementioned applications in my GitHub repository. To follow this article, please fork this repo, clone it locally and checkout nxDeployHeroku entryPoint. Install Heroku CLI To follow this article, you need to have the Heroku CLI installed. Please follow the official installation instruction on the Heroku documentation page here. After you install the CLI, type the following command to log in to Heroku: Deploying NestJS app We're going to start with deploying the NestJS application. The first thing we need to do is creating a Heroku application. Because you need to come up with a unique application name in all the examples, I'll be using ktrz prefix for the app names. Please replace it with your own prefix so that the application names don't collide with each other. To create a Heroku application we can use the following command: Now we need to configure the application to use Node for building the application. This is what buildpacks are for. To add a buildpack, the heroku buildpacks:add command can be used: Heroku uses a Procfile file to specify the commands that are executed on application startup. The default configuration allows for only one Procfile and it has to be in the repository root. For it to work with the monorepo with multiple applications, we need a way to configure multiple Procfiles in the repository. For this purpose, a multi procfile buildpack can be used. We can add it using a similar command to the previous one: Now we can create a Procfile and place it in the directory that makes sense for the monorepo. Let's create the following file: apps/photo/api/Procfile To let the buildpack know about the location of the Procfile , we need to set PROCFILE env variable for the Heroku application. We can do it using the following command: By default, Heroku uses the build script from the package.json file to build the application. We need a more customizable way of building an application so we can configure which application in a monorepo to build. By defining a heroku postbuild script, we tell Heroku to not use a default build one and use our custom script instead. Let's create the following script: package.json As you can see, the PROJECT NAME env variable is used to determine which application to build. It needs to be configured on the Heroku environment: What is left to do is push the changes to a branch and configure Heroku app to use the repository as a source for deployment: To configure the Heroku app, go to the dashboard and choose the application that you've created before: Next, navigate to the Deploy tab, choose the GitHub method, search for your repository, and click Connect: Finally, on the bottom, you can choose to deploy manually from the branch that you've created a moment ago: in package.json add script: package.json To learn more about heroku buildpack nodejs and heroku buildpack multi procfile configuration, please visit the official documentation: heroku buildpack nodejs heroku buildpack multi procfile Deploying Angular app Deploying an Angular app has a lot of similar steps. The Angular application can be served as just static files with routing configured to always point to the root index.html and let Angular handle the rest. We can use another buildpack to accomplish that. heroku buildpack static is configured via static.json file. We can do a basic configuration like so: static.json The example Angular application is configured to use /api proxy for the backend. This also can be configured within static.json file: static.json The last thing to do is configure Heroku to use the static buildpack via the Procfile: apps/photo/fe/Procfile To learn more about heroku buildpack static configuration, please visit the oficial documentation here. Let's commit the changes and configure the second app to use the same GitHub repository: Go to dashboard and choose the frontend application that you've created before. Next, navigate to the Deploy tab, choose GitHub method, search for your repository, and click Connect. Finally, on the bottom you can choose to deploy manually from the branch that you've pushed to a moment ago. After all those steps, you can navigate to your deployed app: Summary If you want to see the result code, you can find it on my GitHub repository. In case you have any questions, you can always tweet or DM me @ktrz. I'm always happy to help!...

Chris Trześniewski5 mins
AngularNestJSHerokuAWS

This Dot AI Field Notes - Anatomy of a Coding Harness

A coding agent is not magic, it’s a loop. We call this a harness. The harness is a deterministic layer of code that wraps an LLM....

1 min
AI

AI Is Speeding Up Development. But Where Are the New Bottlenecks?

AI is accelerating development, but it’s also exposing everything else that’s broken. At the Leadership Exchange, leaders unpacked how AI is reshaping the SDLC and what organizations need to address beyond just coding to make adoption successful. Moderated by Rob Ocel, VP of Innovation at This Dot Labs, the panel featured Itai Gerchikov at Anthropic and Harald Kirschner, Principal Product Manager for GitHub Copilot & VS Code at Microsoft. Panelists explored the current state of AI adoption across the software development lifecycle and shared practical insights into how organizations can effectively integrate AI tools. Panelists discussed how companies are investing in AI tools, skills, and managed competency programs to support developers. While AI can dramatically accelerate coding, the panel emphasized that adoption affects every stage of the SDLC. Bottlenecks now appear in testing, DevOps, product delivery, and marketing as AI speeds up development. Organizations that address technical debt and process inefficiencies are better positioned to extract maximum value from AI tools. The conversation also focused on opportunities and risks. Security, governance, and workforce education were highlighted as critical factors for adoption. Panelists stressed that AI initiatives should be aligned with broader business goals rather than pursued in isolation. They noted that companies experimenting at the cutting edge need to consider organizational readiness just as carefully as technical capabilities. Panelists also explored how leading organizations are navigating the early stages of adoption. Those ahead of the curve are using structured experimentation, prioritizing process improvements, and continuously evaluating outcomes to refine their AI strategies. Learning from these early adopters allows other organizations to anticipate emerging trends and prepare for the next phase of AI adoption rather than simply replicating past approaches. Key Takeaways Investing in AI skills and tools should be done thoughtfully, with clear alignment to business objectives. Examining the full SDLC helps identify bottlenecks that AI may accelerate or expose. Organizations can gain a competitive advantage by learning from early adopters and planning for where AI adoption is heading. AI adoption is not just a technical initiative; it is a strategic transformation that requires attention to people, process, and technology. Organizations that balance innovation with operational discipline will be best positioned to capture the full potential of AI across the software lifecycle. Seeing similar challenges in your own SDLC? Let’s compare notes. Join us at an upcoming Leadership Exchange or reach out to continue the conversation. Tracy can be reached at tlee@thisdot.co....

Calypso Hernandez2 mins
AI AdoptionAILeadership ExchangeEngineering Leadership