Skip to content

Instantly share code, notes, and snippets.

@brentjanderson
Last active May 23, 2024 19:33
Show Gist options
  • Save brentjanderson/dcb59c46023c67c44eb12492b038ff84 to your computer and use it in GitHub Desktop.
Save brentjanderson/dcb59c46023c67c44eb12492b038ff84 to your computer and use it in GitHub Desktop.
Running RedwoodJS on Heroku

Redwood aims to be a serverless framework. But what if you really want to run it on Heroku?

This guide aims to walk you through each piece required to make it work.

Running RedwoodJS On Heroku

  1. Add app.json, Procfile, config/nginx.conf.erb, index.js
  2. yarn workspace api add @redwoodjs/api-server
  3. yarn remove -W @redwoodjs/core && yarn add -W @redwoodjs/core pm2
  4. Update your root package.json with the following scripts:
    "scripts": {
        "build": "rw build",
        "start": "node index.js"
    },
  5. Set apiProxyPath in redwood.toml to apiProxyPath = "/api"

Note that you will need to manually add the heroku/nginx buildpack manually to your app if you are setting this up on an already created Heroku stack.

{
"scripts": {
"postdeploy": "yarn rw db seed"
},
"addons": [
{
"plan": "heroku-postgresql",
"options": {
"version": "12"
}
}
],
"buildpacks": [
{
"url": "heroku/nodejs"
},
{
"url": "heroku/nginx"
}
]
}
var pm2 = require('pm2')
var fs = require('fs')
pm2.start(
{
name: 'my-cool-app-pm2', // Change this to whatever you want
node_args: '-r dotenv/config',
script: './node_modules/@redwoodjs/api-server/dist/index.js',
args: `-f api/dist/functions --socket /tmp/nginx.socket`,
env: {
NODE_ENV: 'production',
},
},
function (err) {
if (err)
return console.error(
'Error while launching applications',
err.stack || err
)
console.log('PM2 and application has been succesfully started')
if (process.env.DYNO) {
console.log(`Signaling to Nginx buildpack that we're ready to go`)
fs.openSync('/tmp/app-initialized', 'w')
}
// Display logs in standard output
pm2.launchBus(function (err, bus) {
console.log('[PM2] Log streaming started')
bus.on('log:out', function (packet) {
console.log('[App:%s] %s', packet.process.name, packet.data)
})
bus.on('log:err', function (packet) {
console.error('[App:%s][Err] %s', packet.process.name, packet.data)
})
})
}
)
# This file must be located at config/nginx.conf.erb
# From the NGINX buildpack: https://github.com/heroku/heroku-buildpack-nginx#customizable-nginx-config
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 {
gzip on;
gzip_comp_level 2;
gzip_min_length 512;
server_tokens off;
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' %>;
include mime.types;
default_type application/octet-stream;
sendfile on;
# Must read the body in 5 seconds.
client_body_timeout 5;
upstream app_server {
server unix:/tmp/nginx.socket fail_timeout=0;
}
server {
server_name _;
listen <%= ENV["PORT"] %>;
keepalive_timeout 5;
location / {
root /app/web/dist;
try_files $uri /index.html;
}
location /api/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server/;
}
}
}
release: yarn rw prisma migrate deploy
web: bin/start-nginx node index.js
@brentjanderson
Copy link
Author

@svenhanssen I've finally tested this out, and you are correct. I've updated the conf file. Thanks!

@wbashir
Copy link

wbashir commented Sep 8, 2021

@svenhanssen am I missing something here? name: 'program-delivery-pm2', // Change this is this supposed to be the same as something else. Having a hard time getting this to deploy.

@brentjanderson
Copy link
Author

@svenhanssen am I missing something here? name: 'program-delivery-pm2', // Change this is this supposed to be the same as something else. Having a hard time getting this to deploy.

That was the name leftover from the project I based this gist on (it was called program-delivery). You can put in anything you like in that field, it doesn't need to match anything else.

What trouble are you having getting it to deploy?

@wbashir
Copy link

wbashir commented Sep 14, 2021

@brentjanderson - I ended up finding my issue being with es6 imports and nothing to do with this set up. Appreciate your response!

@fernandopabst
Copy link

just a note to say this worked (fantastic!) but I had to manually add the nginx buildpack (as https://github.com/heroku/heroku-buildpack-nginx) since it wasn't being picked up through app.json

@brentjanderson
Copy link
Author

just a note to say this worked (fantastic!) but I had to manually add the nginx buildpack (as https://github.com/heroku/heroku-buildpack-nginx) since it wasn't being picked up through app.json

Glad to hear it! On the NGINX buildpack, did you already have an app that you added this to? App.json buildpacks only apply when building a newly-created app. I'll update the instructions with that. 👍 Thanks!

@fernandopabst
Copy link

Glad to hear it! On the NGINX buildpack, did you already have an app that you added this to? App.json buildpacks only apply when building a newly-created app. I'll update the instructions with that. 👍 Thanks!

it was the first deploy in a brand new app. Was quickly fixable, just happy to have my fullstack RedwoodJS running on one heroku dyno :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment