I thought this would be a simple task, but I struggle to find a way to force my webpage to use https. The next.js webapp lives on the heroku servers and I've set up the SSL. Both https and http version works, but how to I force or redirect the website to use the https version. I've seen some solution using express, but nothing in my webapp are using express, is it required? Thanks.
As of Nextjs v12, you can use middleware instead of a setting up a custom server.
Middleware is a better solution for the following reasons:
- a custom server often requires additional dependencies (like express)
- you give up some of the box features like automatic static optimization
- Middleware can be scope to specific paths using the built in routing paradigm
Create a /pages/_middleware.ts
(or .js
) file with something similar to this:
import { NextFetchEvent, NextRequest, NextResponse } from 'next/server'
type Environment = "production" | "development" | "other";
export function middleware(req: NextRequest, ev: NextFetchEvent) {
const currentEnv = process.env.NODE_ENV as Environment;
if (currentEnv === 'production' &&
req.headers.get("x-forwarded-proto") !== "https") {
return NextResponse.redirect(
`https://${req.headers.get('host')}${req.nextUrl.pathname}`,
301
);
}
return NextResponse.next();
}
I also created an npm package for this.
import sslRedirect from 'next-ssl-redirect-middleware';
export default sslRedirect({});
req.nextUrl
should contain the request url from the client perspective. I can confirm this is how it works in heroku (i'm actively using this package and it works). Although there is some odd behavior with nextUrl
github.com/vercel/next.js/issues/31533#issuecomment-1010597076 –
Forebear req.headers.get('host')
returns the true host of the request (e.g. 'yoursite.com'), whereas req.nextUrl.host
will always return 'localhost:3000' (or whichever port you're using) –
Dyche req.headers.get('host')
is more consistently correct, then I'll updates my answer and package to use that (after testing of course) –
Forebear nextUrl
as localhost even on heroku production. I wonder if I'm not seeing that because I'm running a different version of nextjs –
Forebear req.headers.get('host')
always returns localhost:3000 –
Downspout req.headers.get('host')
), but this would only work if your service is responding to requests from a single domain. –
Forebear localhost
, then it sounds like you need to find an alternate header to use. You could maybe have the proxy set a custom header, and then use that instead: req.headers.get('x-redirected-from')
. If you are only serving a single domain, then it seems safer to just store the host in an ENV var –
Forebear req.headers.get("x-forwarded-proto") !== "https")
always evaluated to true because the header was evaluating to "https,http"
. Modifying the provided solution to use .indexOf("https") !== -1
fixed this problem. –
Lima https://${req.headers.get('host')}${req.nextUrl.pathname}${req.nextUrl.search}
, 301); –
Centurion There is a solution with an NPM library called heroku-ssl-redirect
.
First off, install the library using npm i heroku-ssl-redirect
.
Then, create a new server.js
file with the following script.
const next = require('next');
const express = require('express');
const sslRedirect = require('heroku-ssl-redirect').default; // to make it work with 'require' keyword.
const PORT = process.env.PORT || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
// Express's middleware to automatically redirect to 'https'.
server.use(sslRedirect());
server.all('*', (req, res) => {
return handle(req, res);
});
server.listen(port, err => {
if (err) throw err;
console.log(`Server starts on ${PORT}.`);
});
});
Then, change the start
script to be like this:
"scripts": {
"dev": "next",
"build": "next build",
"start": "node server.js"
}
It should work.
Note that you could replace Express with the createServer
method from native Node.js's http
module. But I do this with Express to simplify the syntax.
Further reading: How to setup a custom server in Next.js.
http
module. Oh, and please mark the answer as accepted if it helped you. Thanks 😀. –
Splenius in ur package.json > scripts > "dev":"next dev -experimental-https"
i hope that will help u :)
© 2022 - 2024 — McMap. All rights reserved.