Redirect to Firebase Hosting custom domain - firebase

I have setup a custom domain with Firebase Hosting (eg. myapp.domain.com).
How can one redirect (or turn off) the default Firebase Hosting URL (eg. myapp.firebaseapp.com) so that the app is only accessible from the custom domain?

You cannot turn off the subdomain. Your app will always be available on https://myapp.firebaseapp.com and whatever custom domain you've set up.
To redirect people, you can add a canonical link to your HTML:
<link rel="canonical" href="http://myapp.domain.com/" />
Read more about that in Specify your canonical on the Google Webmaster Central Blog.

You could use Firebase Functions.
Free for 125K invocations/month - https://firebase.google.com/pricing
An example using Express middleware:
// functions/index.js
const functions = require('firebase-functions');
const express = require('express');
const url = require('url');
const app = express();
// Allowed domains
let domains = ['localhost:5000', 'example.com'];
// Base URL to redirect
let baseurl = 'https://example.com/';
// Redirect middleware
app.use((req, res, next) => {
if (!domains.includes(req.headers['x-forwarded-host'])) {
return res.status(301).redirect(url.resolve(baseurl, req.path.replace(/^\/+/, "")));
}
return next();
});
// Dynamically route static html files
app.get('/', (req, res) => {
return res.sendFile('index.html', { root: './html' });
});
// ...
// 404 middleware
app.use((req, res) => {
return res.status(404).sendFile('404.html', { root: './html' });
});
// Export redirect function
exports.redirectFunc = functions.https.onRequest(app);
The exported function name must be added to rewrites in firebase.json e.g.:
{
"hosting": {
"public": "public",
"rewrites": [
{
"source": "**",
"function": "redirectFunc"
}
]
}
}

In addition to specifying canonical link as mentioned in Frank van Puffelen's answer. We can also add front end JavaScript code to do the actual redirect like this without disclosing default url.
if (location.hostname.indexOf('custom.url') === -1) {
location.replace("https://custom.url");
}

Related

Headers are removed from middleware in production Next js

I have such a strange thing. Project on next js 12.3. I use middleware to add canonical link to headers. Everything works locally, and the required headers are added, but when deployed in production, the header I need is not added.
if the subdomain is not www, the canonical must be a link to the www version
import { NextRequest, NextResponse } from 'next/server';
export function middleware(req: NextRequest, res: NextResponse) {
const { protocol, href } = req.nextUrl;
const subdomain = href.replace('https://','').split('.')[0];
if (subdomain !== 'www') {
const urlArr = href?.split('//');
const afterSubdomainUrl = urlArr?.slice(1, urlArr.length)?.join('//');
const response = NextResponse.next();
response.headers.append(
'Link',
`<${protocol}//www.${afterSubdomainUrl}>; rel="canonical"`,
);
return response;
}
}
The problem was at DockerFile - need to implement next code at
app/Dockerfile
COPY middleware.ts /app/middleware.ts
RUN true

How to rewrite homepage based on hostname

I'd like to show two different pages at '/' depending on the hostname (the value for req.hostname). This is because I have a subdomain xxx.mydomain.com that needs to show just one page at the root URL. The idea is to have a CNAME for the subdomain that points to the same server as www. I'm using next version 11.1.2 .
My homepage (/pages/index.js) uses getStaticProps to get data for the page with a revalidate interval of 2 seconds. The page on the production branch works great currently without any rewriting.
I tried using the rewrites option in next.config.js and was able to use this to rewrite all other routes, but rewriting with source: '/' did not do anything. If the source was any other page it worked perfectly. This is pretty much what the next.config.js file looked liken when I tried the rewrite:
const withFonts = require('next-fonts');
const withTM = require('next-transpile-modules')(['#cal-frontends/shared']);
require('dotenv').config({ path: '../../.env' });
module.exports = withTM(withFonts({
async rewrites() {
return [
{
source: '/', // this one still showed the homepage at '/'
destination: '/mission',
},
{
source: '/foo', // this one showed the contact page at '/foo'
destination: '/contact',
},
]
},
webpack(config, options) {
return config;
},
}));
I tried many strategies, including this kind of configuration in server.js
server.get('/',function(req,res){
console.log('trying to redirect', )
console.log('req.hostname', req.hostname)
if (req.hostname === 'mission.mydomain.com') {
console.log('this should show mission', )
return app.render(req, res, '/mission', {})
} else {
handle(req, res);
}
});
This unfortunately did not seem to override the static caching that happens with getStaticProps – you will only see the correct page for the hostname if you load and then reload after it revalidates.
Is there an elegant way to do this?

Next.js redirect www to non www

I have been trying to find a workable solution this searching google but can't find anything solid. I am hosting my Next.js application on Vercel.
When I run a seo check it moans about me having the site available on www and non www and says I should pick one and get it to redirect so in my case, if someone types in www.example.com I would prefer it left of the www.
Since I don't have a htaccess file I can do this in, how would I do it?
Not sure if it matters, but I am using WordPress as my backend aka: Headless Wordpress
You should be able to use host-based redirects now since Next v10.2. See https://nextjs.org/docs/api-reference/next.config.js/redirects#header-cookie-and-query-matching.
In next.config.js:
module.exports = {
// ...
redirects: async () => [
{
source: '/:path*',
has: [{ type: 'host', value: 'www.yourdomain.com' }],
destination: 'https://yourdomain.com/:path*',
permanent: true
}
]
}
you can easily handle permanent redirection in nextjs using the below-mentioned code.
export const getServerSideProps = async (context) => {
const { req, res } = context;
if (req.headers.host.match(/^www/) !== null) {
res.writeHead(301, {
location: "https://" + req.headers.host.replace(/^www./, "") + req.url,
});
res.end();
}
return { props: {} };
};

Setting cache-control header for static file serving on nextjs default server

I am using the default nextjs server to run my nextjs program by this command next start.
However, I am not able to change the cache-control header for the files under the public folder.
Is there any method to set the cache-control header without setting the Custom Server?
There is undocumented feature or bug, but it works. More info can be found here https://nextjs.org/docs/api-reference/next.config.js/headers
Add config to you next.config.js file for example:
async headers() {
return [
{
source: '/:all*(svg|jpg|png)',
locale: false,
headers: [
{
key: 'Cache-Control',
value: 'public, max-age=9999999999, must-revalidate',
}
],
},
]
},
Per this bug report and discussion the Next devs believe static file serving should only be used as a developer convenience, not in production, and hence they don't consider it a priority to add such features.
However, in the issue comments somebody has suggested a workaround using Express to detect requests that will end up serving static files. For example, if the Next.js route handler is the handler() method you can do this to set a one-year cache policy for *.woff font files:
// this is a hack to make the cache headers friendlier..
server.get('*.woff2?', (req, res) => {
res.setHeader('Cache-Control', 'public,max-age=31536000');
return handler(req, res);
});
I'm using Express as a custom server for Next.js, and this is how I set "Cache-Control" header for static files:
const express = require("express");
const server = express();
...
server.use(express.static(__dirname + "/public", { maxAge: "365d" }));
server.use(function (req, res, next) {
if (req.url.match(".js|.css|.woff|.jpg|.png|.gif|.ttf")) {
res.setHeader("Cache-Control", "public,max-age=31536000"); // 365 days
}
next();
});

Access-Control-Allow-Origin Error when trying to add open graph meta tags dynamically via Firebase functions

I'm trying to add open graph meta tags dynamically to my index.html using firebase functions. I'm following this tutorial but because I'd like to allow users to share on their facebook I need to add open graph meta tags on-demand when user wants to share content.
So, it seems to me that running the function via rewrite in firebase.json is not best solution here and I'd like to call the function when user wants to share content to Facebook.
I try to use CORS but it seems I get the "Access-Control-Allow-Origin" error in the browser when I am sending my response back. If I redirect I have no issue. But I need to send the index.html that's been updated. How can I resolve this issue?
Here's my function:
const cors = require('cors')({ origin: true });
const fs = require('fs');
exports.handler = function(req, res) {
cors(req, res, () => {
let indexHTML = fs.readFileSync('./hosting/index.html').toString();
console.log(`#share-fb-formfeed inside cors`, indexHTML);
const ogPlaceholder = '<meta name="functions-insert-dynamic-og">';
res.set('Cache-Control', 'public, max-age=300, s-maxage=600');
res.status(200).send(indexHTML); //results in Access-Control-Allow-Origin
// res.redirect(`https://thekasis.com/feed`); //this works
});
}
Using Rewrites
I also removed cors in my function and here is my firebase.json but I'm not sure if running the Firebase function all the time would be a good idea. It would be ideal to run the function only on-demand when the user is sharing something and so I really like to be able to call the function client side on-demand.
{
"database": {
"rules": "database.rules.json"
},
"hosting": {
"public": "build/es5-bundled",
"rewrites": [{
"source": "**",
"function": "shareContentG-shareToFb"
}]
}
}

Resources