title: Next.js infinite reload from Docker container
body: <p>I'm trying to make a simple Next.js app which uses Firebase auth and runs from a Docker container.</p>
  
  <p>The following works fine locally (running from a built docker container). However, when I deploy to Heroku or Google Cloud Run and go to the website, it results in an infinite reload loop (page just freezes up and eventually runs out of memory. It works fine when being served as a Node.js app from Google App Engine. </p>
  
  <p>I think the error is in the Dockerfile (I think I'm doing something wrong with the ports). Heroku and Google Cloud Run randomize their <code>process.env.PORT</code> environment variable, if that's any use, and ignore Docker's <code>EXPOSE</code> commands as far as I'm aware. </p>
  
  <p>No errors are shown in Network / Console when the reloads are happening. I thought it was due to Next.js 8's hot module reload, but the issue persists on Next.js 7 as well. </p>
  
  <p>The relevant files are below. </p>
  
  <h2>Dockerfile</h2>
  
  <pre><code>FROM node:10
  
  WORKDIR /usr/src/app
  
  COPY package*.json ./
  RUN yarn
  
  # Copy source files.
  COPY . .
  
  # Build app.
  RUN yarn build
  
  # Run app.
  CMD [ "yarn", "start" ]
  </code></pre>
  
  <h2>server.js</h2>
  
  <pre><code>require(`dotenv`).config();
  
  const express = require(`express`);
  const bodyParser = require(`body-parser`);
  const session = require(`express-session`);
  const FileStore = require(`session-file-store`)(session);
  const next = require(`next`);
  const admin = require(`firebase-admin`);
  const { serverCreds } = require(`./firebaseCreds`);
  
  const COOKIE_MAX_AGE = 604800000; // One week.
  
  const port = process.env.PORT;
  const dev = process.env.NODE_ENV !== `production`;
  const secret = process.env.SECRET;
  
  const app = next({ dev });
  const handle = app.getRequestHandler();
  
  const firebase = admin.initializeApp(
    {
      credential: admin.credential.cert(serverCreds),
      databaseURL: process.env.FIREBASE_DATABASE_URL,
    },
    `server`,
  );
  
  app.prepare().then(() =&gt; {
    const server = express();
  
    server.use(bodyParser.json());
    server.use(
      session({
        secret,
        saveUninitialized: true,
        store: new FileStore({ path: `/tmp/sessions`, secret }),
        resave: false,
        rolling: true,
        httpOnly: true,
        cookie: { maxAge: COOKIE_MAX_AGE },
      }),
    );
  
    server.use((req, res, next) =&gt; {
      req.firebaseServer = firebase;
      next();
    });
  
    server.post(`/api/login`, (req, res) =&gt; {
      if (!req.body) return res.sendStatus(400);
  
      const { token } = req.body;
      firebase
        .auth()
        .verifyIdToken(token)
        .then((decodedToken) =&gt; {
          req.session.decodedToken = decodedToken;
          return decodedToken;
        })
        .then(decodedToken =&gt; res.json({ status: true, decodedToken }))
        .catch(error =&gt; res.json({ error }));
    });
  
    server.post(`/api/logout`, (req, res) =&gt; {
      req.session.decodedToken = null;
      res.json({ status: true });
    });
  
    server.get(`/profile`, (req, res) =&gt; {
      const actualPage = `/profile`;
      const queryParams = { surname: req.query.surname };
      app.render(req, res, actualPage, queryParams);
    });
  
    server.get(`*`, (req, res) =&gt; handle(req, res));
  
    server.listen(port, (err) =&gt; {
      if (err) throw err;
      console.log(`Server running on port: ${port}`);
    });
  });
  </code></pre>
  
  <h2>_app.js</h2>
  
  <pre><code>import React from "react";
  import App, { Container } from "next/app";
  import firebase from "firebase/app";
  import "firebase/auth";
  import "firebase/firestore";
  import "isomorphic-unfetch";
  import { clientCreds } from "../firebaseCreds";
  import { UserContext } from "../context/user";
  import { login, logout } from "../api/auth";
  
  const login = ({ user }) =&gt; user.getIdToken().then(token =&gt; fetch(`/api/login`, {
    method: `POST`,
    headers: new Headers({ "Content-Type": `application/json` }),
    credentials: `same-origin`,
    body: JSON.stringify({ token }),
  }));
  
  const logout = () =&gt; fetch(`/api/logout`, {
    method: `POST`,
    credentials: `same-origin`,
  });
  
  class MyApp extends App {
    static async getInitialProps({ ctx, Component }) {
      // Get Firebase User from the request if it exists.
      const user = getUserFromCtx({ ctx });
      const pageProps = Component.getInitialProps ? await Component.getInitialProps({ ctx }) : {};
      return { user, pageProps };
    }
  
    constructor(props) {
      super(props);
      const { user } = props;
      this.state = {
        user,
      };
  
      if (firebase.apps.length === 0) {
        firebase.initializeApp(clientCreds);
      }
    }
  
    componentDidMount() {
      firebase.auth().onAuthStateChanged((user) =&gt; {
        if (user) {
          login({ user });
          return this.setState({ user });
        }
      });
    }
  
    doLogin = () =&gt; {
      firebase.auth().signInWithPopup(new firebase.auth.GoogleAuthProvider());
    };
  
    doLogout = () =&gt; {
      firebase
        .auth()
        .signOut()
        .then(() =&gt; {
          logout();
          return this.setState({ user: null });
        });
    };
  
    render() {
      const { Component, pageProps } = this.props;
  
      return (
        &lt;Container&gt;
          &lt;UserContext.Provider
            value={{
              user: this.state.user,
              login: this.doLogin,
              logout: this.doLogout,
              userLoading: this.userLoading,
            }}
          &gt;
            &lt;Component {...pageProps} /&gt;
          &lt;/UserContext.Provider&gt;
        &lt;/Container&gt;
      );
    }
  }
  
  export default MyApp;
  </code></pre>
  
  <h2>Update:</h2>
  
  <p>Reproducible repo code is <a href="https://github.com/colinricardo/next-issue" rel="nofollow noreferrer">here</a>. </p>
  
  <p>Instructions are in the README, and it works fine locally. </p>