Proxy Heroku App Running Next.js and Prisma Client - heroku

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/

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 :
Download QGTunnel into the root of your project
curl https://s3.amazonaws.com/quotaguard/qgtunnel-latest.tar.gz | tar xz
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.
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.
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".
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.
If you have problems...
Enable the environment variable QGTUNNEL_DEBUG=true and then restart your application while watching the logs.
VERY IMPORTANT
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.

Related

Laravel 9 (Vite) shared on local network on https

I am building a web app that uses (mobile devices's) camera, but this is working only on https and localhost.
The web app is served locally using WAMP 3.2.9.
I've managed to use the secure protocol (https) within my wamp configuration, but I'm having problems when I want to share my app to my local network so I can view the app on my phone and test the camera functionality.
In the older versions of Laravel (which used webpack) this was very easy using browsersync, but now, using Vite I don't know exactly how to do this.
My local domain is myapp.test and can be accessed using both http and https.
I tried to use npm run vite --host, which shows the local and network address as well (ex. 192.168..), but when I visit that address on my phone, I can see only the Vite default page This is the Vite development server that provides Hot Module Replacement for your Laravel application., but not the app itself.
In my vite.config.js file I added that ip from vite network:
server: {
https: true,
host: '192.168._._'
},
plugins: [
laravel({
input: [
'resources/css/app.css',
'resources/js/app.js',
],
refresh: [
...refreshPaths,
'app/Http/Livewire/**',
],
}),
mkcert()
],
Note that I also used the mkcert vite plugin to allow me to use https.
Now I'm confused about the vite service that runs on port 5173 by default and the app that should run on port 443 to be on https.
I've also tried using `php artisan serve --host 192.168.. which works on my local network, but it doesn't work with https, so I had to focus on WAMP only.
So how can I have my app shared among my local network with https?
I'll explain about how Vite works compared to Webpack to hopefully help you understand a little better.
Both Webpack and Vite create a bundle of files when using the build commands to compile for production. Using the dev command, that it seems like you're using, they work a little differently. While Webpack watches for file changes to recompile the bundle and BrowserSync then reloads your assets for you, Vite starts a local server to serve the compiled files. This means that you don't proxy your original domain like with BrowserSync. Vite also creates a file in your public folder called "hot", which tells Laravel which url it should use when using the #vite() directive or the Vite::asset() method. Because of that you can use your original domain myapp.test even for the hot reloading of the dev command. I don't think Laravel actually supports --host and if it doesn't I haven't been able to find it or figure it out.
I did find https://github.com/Applelo/vite-plugin-browser-sync to hopefully solve your testing on other devices but I couldn't get it to work with https, otherwise I'm afraid you might have to look into something like ngrok and use the npm run build command instead of dev until better support is built into Laravel.
Update:
To configure the BrowserSync plugin you have to manually configure the proxy:
VitePluginBrowserSync({
bs: {
proxy: 'http://myapp.test/' // The usual access URL
}
})
Since it doesn't seem like Laravel supports --host I have been able to find a workaround: because Laravel reads the asset host URL from the hot file in the public directory, you can replace the contents with the external Vite URL like http://192.168.1.37:5174 after running npm run dev --host. This will make Laravel use that URL when referencing any assets.

Using SpringBoot, NodeJS and Vue-CLI - not saved session

I have been using SpringBoot for web development before, which needs to manage session, database, HTML and other functions.
Recently, I am going to use VUE, replacing the HTML part of SpringBoot.
Now I use the following two methods for development, but I am troubled by problems such as cross domain and session cannot be keeped.
Use nodejs as the enter of the website and use vue.config to configure the agent. In this way, the URL located is correct, but the login status cannot be saved.For example, if submit a form for login, the background returns to the successful message for login, but if refresh the page, it will show 'not login'. The 'devServer' configuration is as follows
devServer: {
open: false,
host: 'localhost',
port: 8080,
proxy: {
'/ API: {
Target: 'http://192.168.9.211/',
ChangeOrigin: true,
ws: true,
PathRewrite: {
'^ / API' : ' '
},
cookieDomainRewrite: 'localhost',
}
}
}
Use Nginx as gateway, and then forward the HTML request to NodeJS, and the data request (such as JSON data) to SpringBoot.I haven't had time to experiment with this idea, because it may still occur session saving issues.Nginx is forwarding HTTP requests to Nodejs and SpringBoot, so this saved session is from Nodejs or SpringBoot?
So ask if anyone has done a similar project and if you can share your experience.

"Not allowed to request resource" in Safari and "Blocked loading mixed active content" in Firefox. Perfect functionality in Chrome

I am working on an app using a React frontend and Express backend, with GraphQL setup through Apollo (I am following and modifying tutorial https://www.youtube.com/playlist?list=PLN3n1USn4xlkdRlq3VZ1sT6SGW0-yajjL)
I am currently attempting deployment, and am doing so with Heroku. Everything functions perfectly on my local machine before deployment and on Heroku in Google Chrome. However, I get the aforementioned errors in Safari and Firefox, respectively. Wondering why this is happening in these browsers and how to fix.
I have spent about 10 hrs doing research on this. Things I tried that made no difference:
I tried adding CORS to my express backend
I tried serving the graphql endpoint as HTTPS
Moving app.use(express.static) in main app.js server file
I couldn't find many other things to try. Everywhere I looked seemed to say that CORS fixed the problem, but mine persists.
Github link: https://github.com/LucaProvencal/thedrumroom
Live Heroku App: https://powerful-shore-83650.herokuapp.com/
App.js (express backend):
const cors = require('cors')
// const fs = require('fs')
// const https = require('https')
// const http = require('http')
app.use(express.static(path.join(__dirname, 'client/build')));
app.use(cors('*')); //NEXT TRY app.use(cors('/login')) etc...
app.use(cors('/*'));
app.use(cors('/'));
app.use(cors('/register'));
app.use(cors('/login'));
app.get('/login', (req, res) => {
res.sendFile(path.join(__dirname, "client", "build", "index.html"));
});
app.get('/register', (req, res) => {
res.sendFile(path.join(__dirname, "client", "build", "index.html"));
});
server.applyMiddleware({ app }); // app is from the existing express app. allows apollo server to run on same listen command as app
const portVar = (process.env.PORT || 3001) // portVar cuz idk if it will screw with down low here im tired of dis
models.sequelize.sync(/*{ force: true }*/).then(() => { // syncs sequelize models to postgres, then since async call starts the server after
app.listen({ port: portVar }, () =>
console.log(`🚀 ApolloServer ready at http://localhost:3001${server.graphqlPath}`)
)
app.on('error', onError);
app.on('listening', onListening);
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
Full file is on Github, I tried to post only relevant parts above.
The expected result is that it works in all browsers. It seems from my research that since Heroku serves on HTTPS, Safari and Firefox do not allow requests to HTTP (which is where the graphql server is located, http://localhost:3001/graphql'). When I tried serving Apollo on HTTPS, Heroku just crashed, giving me H13 and 503 errors.
Thanks for any help...
This may also happen during local development when running the front end using HTTPS, but the back end using HTTP.
This is because CORS treats two URLs as having the same origin "only when the scheme, host, and port all match". Matching scheme means matching protocols e.g. both http, or both https.
One solution for local development is to proxy the back end using a tool such as ngrok.
Suppose the front end uses an environment variable which indicates the back end's URL:
BACK_END_API_URL=http://localhost:3005. Then do the following.
Install ngrok
Identify what port the back end is running on e.g. 3005
Run ngrok http 3005 at the command line, which will establish both http and https endpoints. Both will ultimately proxy the requests to the same back end endpoint: http://localhost:3005
After running ngrok it will display the http and https endpoints you can use. Put the one that matches the front end protocol you're using (e.g. https) into your front end environment variable that indicates the back end's URL e.g.
BACK_END_API_URL=https://1234asdf5678ghjk.ngrok.io
Was going to delete this because it is such a silly problem but maybe it will help someone in the future:
I simply replaced all of my 'http://localhost:PORT' endpoints in development with '/graphql'. I assumed that localhost meant local the machine running the code. But an app running on Heroku does not point to localhost. The express server is served on the url (https://powerful-shore-83650.herokuapp.com/) in our case...
At any rate I am so glad I came to a solution. I have a full stack app deployed and connected to a db. Hopefully this post can save someone lots of time.

Google Compute Engine websocket secure (wss//) setting

I need help to enable wss in with google compute engine instance ip. My google cloud compute engine instance ip is: 35.192.96.70
I started ratchet server like this:
$allowed_origins = ['localhost','35.192.96.70', '127.0.0.1'];
$app = new Ratchet\App('35.192.96.70', 8080, '0.0.0.0');//App(hostname, port, 'whoCanConnectIP', '')
$app->route('/comm', new Comm, $allowed_origins);
$app->run();
and in js file I'm connecting to websocket server like this:
const wsChat = new WebSocket("wss://35.192.96.70:8080/comm");
but its not connecting. But if I use 'ws' instead of 'wss' like this:
const wsChat = new WebSocket("ws://35.192.96.70:8080/comm");
then its working.
I need help how to make wss work. What changes/settings I need to do in google cloud dashboard or in apache setting or else ?
Thanks for help,
If on SSL, Ratchet won't work unless you make some changes on your server.
Enable mod_proxy.so
Enable mod_proxy_wstunnel.so
Open httpd.conf and add this: ProxyPass /wss2/ ws://YOUR_SERVER_IP_OR_DOMAIN:PORT/
e.g. ProxyPass /wss2/ ws://www.abc.xyz:8080/
From your front-end, you can connect like this:
const wsChat = new WebSocket("wss://YOUR_SERVER_IP_OR_DOMAIN/wss2/comm");
However, if you are wondering how to edit httpd.conf on WHM, here is how:
After enabling those services (mod_proxy.so and mod_proxy_wstunnel.so), log in to WHM,
go to "service configuration" => "Apache configuration" => "include editor" => "pre main include",
select a version of your choice or choose "All versions". The file name should be "pre_main_global.conf'
All your new configuration can be written in that textarea without tampering with httpd.conf directly. The configurations will be loaded on Apache start-up.
Once you put the Proxypass directive there, restart your server and there you go.

Vue Cli Webpack Proxy

I've been developing with the vue-cli and the Webpack template. Everything works flawlessly but I'm having some issues using a custom host. Right now Webpack listens to localhost:8080 (or similar) and I want to be able to use a custom domain such as http://project.dev. Has anybody figured this out?
This might be where the problem resides:
https://github.com/chimurai/http-proxy-middleware
I also added this to the proxyTable:
proxyTable: { 'localhost:8080' : 'http://host.dev' } and it gives me a console response [HPM] Proxy Created / -> http://host.dev
Any advice, direction or suggestion would be great!
Update
I successfully added a proxy to my Webppack project this way:
var mProxy = proxyMiddleware('/', {
target: 'http://something.dev',
changeOrigin: true,
logLevel: 'debug'
})
app.use(mProxy)
This seems to work, but still not on port 80.
Console Log:
[HPM] Proxy created: / -> http://something.dev
I can assume the proxy is working! But my assets are not loaded when I access the url.
Is important to note I'm used to working with Mamp -- and its using port 80. So the only way I can run this proxy is to shut down Mamp and set the port to 80. It seems to work, but when I reload page with the proxy URL -- there is a little delay, trying to resolve, and then console outputs this:
[HPM] GET / -> http://mmm-vue-ktest.dev
[HPM] PROXY ERROR: ECONNRESET. something.dev -> http://something.dev/
And this displays in the browser:
Error occured while trying to proxy to: mmm-vue-ktest.dev/
The proxy table is for forwarding requests to another server, like a development API server.
If you want the webpack dev server to run on this address, you have to add it to your OS's hosts file. Vue or we pack can't do this, it's the job of your OS.
Google will have simple guides for every OS.

Resources