Proxy Heroku App Running Next.js and Prisma Client

586 views Asked by At

I am trying to use QuotaGuard Static IPs to host a Next.js application. The Next API routes are running Prisma which, in turn is making direct db requests to a protected Microsoft SQL Server.

The client has whitelisted my IP for local development and the app works fine. But on Heroku you can't get a static IP without the QuotaGard.

I don't believe I have set up the QuotaGuard correctly or the server.js file. The rest of the app is working fine. Here are those files:

Expected Behavior:

  • The server proxies its url to one provided by the QuotaGuard
  • The MS Sql Server can whitelist the IP
  • Next.js server.js uses the 'http-proxy-middleware' to proxy requests

Actual Behavior:

  • The app homepage just shows 'this is a proxy server'
  • The QuotaGuard dashboard does not show any requests
  • The prisma client cannot connect (connection refused)
// server.js
//  BASICALLY A COMBO OF THESE TWO OPTIONS:
//  - https://quotaguard.freshdesk.com/support/solutions/articles/5000013744-getting-started-with-node-js-standard-http-library-quotaguard
//  - https://medium.com/bb-tutorials-and-thoughts/next-js-how-to-proxy-to-backend-server-987174737331

const express = require('express')
const { parse } = require('url')
const next = require('next')
const { createProxyMiddleware } = require('http-proxy-middleware')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

// proxy middleware options
const options = {
    target: process.env.QUOTAGUARDSTATIC_URL, // target host
    changeOrigin: true, // needed for virtual hosted sites
    ws: true, // proxy websockets
}

app.prepare()
    .then(() => {
        const server = express()

        if (!dev) {
            server.use('*', createProxyMiddleware({ ...options  }))
        }

        server.all('*', (req, res) => {
            const parsedUrl = parse(req.url, true)
            return handle(req, res, parsedUrl)
        })

        server.listen(process.env.PORT, (err) => {
            if (err) throw err
            console.log(`> Ready on http://localhost:${process.env.PORT}`)
        })
    })
    .catch((err) => {
        console.log('Error:::::', err)
    })

You can see the live app at https://planes-planner-staging.herokuapp.com/

1

There are 1 answers

0
QuotaGuard On

In this case, based on what you shared, you are close, but you need to go with the SOCKS proxy using the QuotaGuard QGTunnel software.

Steps to set that up are :

  1. Download QGTunnel into the root of your project
curl https://s3.amazonaws.com/quotaguard/qgtunnel-latest.tar.gz | tar xz
  1. Log in to the QuotaGuard dashboard and setup the tunnel

Since you are using Heroku, you can use the Heroku CLI to log into the dashboard with the following command:

 heroku addons:open quotaguardstatic  

Or if you prefer, you can login from the Heroku dashboard by clicking on QuotaGuard Static on the resources tab of your application.

Once you are logged into the dashboard, in the top right menu, go to Setup (Gear Icon), click on QGTunnel Configuration, then Create Tunnel.

Remote Destination: tcp://hostname.for.your.server.com:1433 
Local Port: 1433
Transparent: true
Encrypted: false

This setup assumes that the remote mssql server is located at hostname.for.your.server.com and is listening on port 1433. This is usually the default port.

The Local Port is the port number that QGTunnel will listen on.

In this example we set it to 5432, but if you have another process using 1433, you may have to change it (ie: 1434).

Transparent mode allows QGTunnel to override the DNS for hostname.for.your.server.com to 127.0.0.1, which redirects traffic to the QGTunnel software. This means you can connect to either hostname.for.your.server.com or 127.0.0.1 to connect through the tunnel.

Encrypted mode can be used to encrypt data end-to-end, but if your protocol is already encrypted then you don't need to spend time setting it up.

  1. Change your code to connect through the tunnel

With transparent mode and matching Local and Remote ports you should not need to change your code. You can also connect to 127.0.0.1:1433.

Without transparent mode, you will want to connect to 127.0.0.1:1433.

  1. Change your startup code

Change the code that starts up your application. In Heroku, this is done with a Procfile. Basically you just need to prepend your startup code with "bin/qgtunnel".

So for a Procfile that was previously:

    web: your-application your arguments

you would now want:

    web: bin/qgtunnel your-application your arguments  

If you do not have a Procfile, then Heroku is using a default setup in place of the Procfile based on the framework or language you are using. You can usually find this information on the Overview tab of the application in Heroku's dashboard. It is usually under the heading "Dyno information".

  1. Commit and push your code

Be sure that the file bin/qgtunnel is added to your repository.

If you are using transparent mode, be sure that vendor/nss_wrapper/libnss_wrapper.so is also added to your repository.

If you are not using transparent mode, you will want to set the environment variable QGTUNNEL_DNSMODE to DISABLED to avoid seeing an error message in your logs.

  1. If you have problems...

Enable the environment variable QGTUNNEL_DEBUG=true and then restart your application while watching the logs.

VERY IMPORTANT

  1. After you get everything working

Download your QGTunnel configuration from the dashboard as a .qgtunnel file and put that in the root of your project. This prevents your project from relying on the QG website during startup.

Alternatively you can put the contents of the downloaded configuration file in a QGTUNNEL_CONFIG environment variable.