Reverse Proxy Sending 127.0.0.1 as URL, instead of external site-url.com to oauth callback - apache

I am transferring a site from the defunct OpenShift v2, to LightSail on AWS. I have the app up and running on LightSail at localhost:3333, forwarded externally. I am able to pull up the site using the site-url.com
However, when attempting to login to the app (using Passport Facebook). The callback url is getting set to 127.0.0.1, instead of the whitelisted (facebook dev) www.site-url.com
https://www.facebook.com/dialog/oauth?response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A3333%2Fauth%2Fwww.site-url.com%2Fauth%2Ffacebook%2Fcallback&scope=email&client_id=XXX
Relevant login code:
const appUrl = "www.site-url.com";
const callbackURL = appUrl + "/auth/facebook/callback";
passport.use(new FacebookStrategy({
clientID: clientID,
clientSecret: clientSecret,
callbackURL: callbackURL,
profileFields: ['id', 'displayName', 'email']
},
...
app.get('/auth/facebook',
passport.authenticate('facebook', { scope: ['email'] }));
app.get('/auth/facebook/callback',
passport.authenticate('facebook',{
successRedirect: appUrl + '/profile',
failureRedirect: appUrl + '/?login-failed'}
));
I added appUrl, in an attempt to fix it via server code. However, I have a feeling Apache would be better suited at fixing this.
I setup the Proxy, following these instructions, and tried all variations of 127.x/site-url.com
ProxyPass / http://127.0.0.1:3333/
# ProxyPass / http://www.site-url.com/
ProxyPassReverse / http://127.0.0.1:3333/
# ProxyPassReverse / http://www.site-url.com/
Anyone have any ideas?

Turning on PreserveHost solved the issue, Facebook is now receiving the correct callback url
PreserveHost:
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:3333/
ProxyPassReverse / http://127.0.0.1:3333/
Apache config:
vim /opt/bitnami/apache2/conf/bitnami/bitnami-apps-prefix.conf
Append: Include "/home/bitnami/conf/httpd-app.conf
Start up the app using screen to avoid shutdown when SSH process is killed. Maybe try nodemon for resiliency
Thanks, #DusanBajic!

Related

Heroku Express / Nextjs client cookie not being set

So I'm having a bit of an issue where I have two apps hosted on Heroku the first being an Express application with the following cookie settings
const cookieSettings = {
maxAge: expiryTime,
...cookieOptions || {},
// For security these properties should always remain below the spread
httpOnly: true,
secure: process.env.NODE_ENV !== "development",
sameSite: "none",
path: "/",
}
And a Nextjs app which has some middleware that uses the cookie for login control to protect routes.
Locally I have no issues with the following login logic within the login route which sets the cookie browser side
const cookie = getCookie({ tokenOptions: { id: user._id } });
res.setHeader("Set-Cookie", cookie);
return res.sendStatus(200);
I have read there is issues with Heroku as it's on the public list of domains so the browser wont set if it comes from this but the issue I'm having is on a custom domain. My domain is https://www.mydomain.co.uk but for some reason I can't get it to set when I'm on this domain.
When using Postman I do get the cookie back but the domain comes from my API domain ie api.reviewcircle.co.uk which I think is why the browser isn't setting the cookie as the domains don't match but I can't find any info on how to fix this so would be great if anyone has any ideas.
You can see the cookie is included in the response but isn't set:

How can I make my nextjs with Express site work on ssl

We have a site running on Next.js and Express. This is on a cPanel server with Aapche and together with nginx serving as reverse proxy.
I need to have ssl on the site. But I am quite confuused with how the configurations should be.
My server.js :
const express = require('express')
const next = require('next')
const https = require('https');
const fs = require('fs');
//const forceSSL = require('express-force-ssl')
var ssl_options = {
key: fs.readFileSync('/home/myreactsite.key'),
cert: fs.readFileSync('/home/myreactsite.crt'),
};
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
const favicon = require('serve-favicon')
const path = require('path')
app.prepare()
.then(() => {
const server = express()
server.use(favicon(path.join(__dirname, 'static', 'images', 'favicon.ico')))
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(3007, (err) => {
if (err) throw err
console.log('> Ready on http://localhost:3007')
})
var httpsServer = https.createServer(ssl_options,server).listen('8445', (err) => {
if (err) throw err
console.log('> Ready on https://localhost:8445')
})
})
.catch((ex) => {
console.error(ex.stack)
process.exit(1)
})
Apache runs on 8080
Nginx runs on 80
Next.js runs on both 3007 and 8445(I prefer it for ssl)
My Apache config contains the following to hide the port 3007
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://myreactsite.com:3007/
The site works fine if I access it as http://myreactsite.com . But it fails when I access https://myreactsite.com though I can access https version by specifying the port number as https://myreactsite.com:8445
I want to make it work without specifying the https port.
How can I get my site to force all pages to https without specifying the port?
You probably want to use Apache for all the SSL handling and listen to the 443 port, then proxy to your 3007 port. Try this config:
<VirtualHost *:443>
ProxyPreserveHost On
ProxyRequests Off
ServerName myreactsite.com
ServerAlias myreactsite.com
ProxyPass / http://0.0.0.0:3007/
ProxyPassReverse / http://0.0.0.0:3007/
SSLEngine On
SSLProxyEngine On
SSLCertificateFile /home/myreactsite.crt
SSLCertificateKeyFile /home/myreactsite.key
</VirtualHost>
To redirect all HTTP traffic then:
<VirtualHost *:80>
ServerName myreactsite.com
Redirect / https://myreactsite.com/
</VirtualHost>
Based on #fabian comment, I am posting my working configurations if it helps someone...
Added the following lines in the 443 virtual host section for the site in apache.conf :
ProxyPreserveHost On
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://example.com:3000/
ProxyPassReverse / http://example.com:3000/
SSLProxyEngine On
#To redirect to https and www version
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L]
Also, added the following line in the nginx vhost file for the site :
server {
...
...
#To redirect all http requests to https+www
return 301 https://www.example.com$request_uri;
...
...
}

Redirecting to relative path using Laravel 4

Is it possible, in Laravel 4.1, to redirect to a relative path instead of the full path ? If we look at the UrlGenerator::to method, here what we have:
public function to($path, $extra = array(), $secure = null)
{
if ($this->isValidUrl($path)) {
return $path;
}
$scheme = $this->getScheme($secure);
$tail = implode('/', array_map('rawurlencode', (array) $extra));
$root = $this->getRootUrl($scheme);
return $this->trimUrl($root, $path, $tail);
}
This will act like this (meta-code):
mysite.com/url Redirect::to('/test'); => mysite.com/test
What I'd want it's to be redirected to a relative URL:
mysite.com/url Redirect::to('/test'); => /test
The problem it's that the company I'm working for, use a ReverseProxy to redirect all the traffic to HTTPS protocol, and with this kind of laravel redirects I keep getting redirected from HTTP to HTTPS :
call: GET http:// mysite.com
proxy: GET https:// mysite.com
redirect to login: GET http:// mysite.com / login
proxy: GET https:// mysite.com / login
submit login: POST http:// mysite.com / login
proxy: POST https:// mysite.com / login
And the problem is that the submit form fail.
Is there a possibility to redirect to the relative path and let the proxy define the root url / protocol to use ?
I'm on Laravel 4.2, I'm using Redirect::away('/test'), not sure if the function is there yet on Laravel 4.1.

basic app + express + mongodb + how to not use the port?

This is a basic app I have got that uses express for setting up routes and and also does some query on a mongo db
If I go to http://localhost:8080/ whatever is in the views/hello.html will be displayed in the browser.
If i go to http://localhost:8080/test 'This is a test Page' will be displayed in the browser.
My question is why do I have to specify the port 8080 in the address? Or put another way how do I display what i want at this address http://localhost/ without specifying the port?
I know I can change the port by changing the value of 8080 here
app.listen(8080);
basic app below:
var express = require('express'),
app = express(),
cons = require('consolidate'),
crypto = require('crypto'),
MongoClient = require('mongodb').MongoClient;
app.engine('html', cons.swig);
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
MongoClient.connect('mongodb://localhost:27017/m101', function(err, db) {
if(err) throw err;
//set up a route to go to the page http://localhost:8080/ to see 'This is a test Page'
app.get('/', function(req, res){
db.collection('hw1_3').findOne(function(err, doc) {
//do stuff here
return res.render('hello', { "name" : decrypted });
});
});
//set up a route to go to the page http://localhost/test to see 'This is a test Page'
app.get('/test', function(req, res){
return res.send('This is a test Page!!', 200);
});
app.listen(8080);
console.log('Express server started on port 8080');
});
The default port for http traffic is 80. If you bind to any port other than 80, you need to specify the port in the URL. app.listen(80) will take care of your problem.
On Unixy systems, root (administrator) access is required to bind to any port less than 1024, so you'll have to run your server like sudo node server.js to get port 80. You should bind to a higher port (like 8080) in this case while developing on your machine.
I'm pretty noob, but I'd say that localhost:8080 displays in place of www.somesite.com. I wouldn't get too wrapped up in the port number. If you deploy it to heroku or something you wont see it.

ProxyPassReverse doesn't rewrite Location (http header)

I have an apache installed in a frontend server (server1), which is as reverse proxy. I have another server (server2) with tomcat that is running a webapp.
I configured my reverse proxy (server1) like that:
ProxyPass /app1/ ajp://server2:8009/app1/
ProxyPassReverse /app1/ https://www.external_domain_name.com/
When I connect to:
https://www.external_domain_name.com/app1/
my web app is working properly. In some pages, the web app redirects me (302) to another page.
Then, I am redirected to :
https://server1_internal_ip/app1/foo_bar
When I look to the http headers, the response header contains:
Status code: 302
Location: https://server1_internal_ip/app1/foo_bar
So, my conclusion ProxyPass is working properly, but the ProxyPassReverse is not.
Can you help me please to understand what's going wrong?
Thanks
Actually ProxyPassReverse will replace the Location which your server returned.
Example 1 (Only URL Path)
Apache2 Setting
ProxyPass "/8080" "http://localhost:8080"
ProxyPassReverse "/8080/" "/"
Node.js Setting
const express = require("express");
const app = express()
app.get('/', (req, res) => {
res.json({a: 8080})
})
app.get("/hi", (req, res) => {
res.json({a: "8080hi"})
})
app.get("/redirect", (req, res) => {
res.redirect("/hi")
})
app.listen(8080)
Original Location is "Location: /hi".
New one is "Location: /8080/hi". (/ => /8080/)
That means Apache2 replaced the Location value with ProxyPassReverse setting.
Or you can use full FQDN to do it.
Example 2 (FQDN)
Apache2 Setting
ProxyPass "/8080" "http://localhost:8080"
ProxyPassReverse "/8080" "http://localhost:8080"
Node.js Setting
const express = require("express");
const app = express()
app.get('/', (req, res) => {
res.json({a: 8080})
})
app.get("/hi", (req, res) => {
res.json({a: "8080hi"})
})
app.get("/redirect", (req, res) => {
res.setHeader("Location", "http://localhost:8080/hi")
res.send(302)
})
app.listen(8080)
Apache2 will convert http://localhost:8080/hi to http://localhost/8080/hi.
(If my Apache2 is configured to 80 port.)
Set it to this instead
ProxyPassReverse /app1/ ajp://server2:8009/app1/
Seemed to work for me when I came across a similar problem.