title: Nuxt.js SSR w/ Nest API deployed to AWS in a Docker container
body: <p>I've tried roughly 5 million variations on the theme here, as well as spent a lot of time poring through the Nuxt docs and I cannot get Nuxt SSR with a Nest backend working when deployed in a docker container to AWS. Below is my current setup. Please let me know if I've left anything out.</p>
  
  <p>Here are the errors I'm getting:</p>
  
  <p><a href="https://www.noticeeverythingcreative.com/contact" rel="nofollow noreferrer">https://www.noticeeverythingcreative.com/contact</a>
  This route makes a <code>POST</code> request for page meta to <code>https://www.noticeeverythingcreative.com/api/contact/meta</code> in the component's <code>asyncData</code> method. This produces a big old error from Axios. Below is the part I think is relevant, but let me know if you need more.</p>
  
  <pre><code>{
    errno: 'ECONNREFUSED',
    code: 'ECONNREFUSED',
    syscall: 'connect',
    address: 'xxx.xx.x.x', // IP Address of the docker container
    port: 443,
    config: {
      url: 'https://www.noticeeverythingcreative.com/api/contact/meta',
      method: 'post',
      headers: {
        Accept: 'application/json, text/plain, */*',
        connection: 'close',
        'x-real-ip': 'xx.xxx.xxx.xxx', // My IP
        'x-forwarded-for': 'xx.xxx.xxx.xxx', // My IP
        'x-forwarded-proto': 'https',
        'x-forwarded-ssl': 'on',
        'x-forwarded-port': '443',
        pragma: 'no-cache',
        'cache-control': 'no-cache',
        'upgrade-insecure-requests': '1',
        'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36',
        'sec-fetch-user': '?1',
        'sec-fetch-site': 'same-origin',
        'sec-fetch-mode': 'navigate',
        'accept-encoding': 'gzip, deflate',
        'accept-language': 'en-US,en;q=0.9',
        'Content-Type': 'application/json'
      },
      baseURL: 'https://www.noticeeverythingcreative.com'
    }
  </code></pre>
  
  <p>Here's the relevant part of my <code>nuxt.config.js</code>:</p>
  
  <pre><code>mode: 'universal',
  srcDir: './src',
  rootDir: './',
  modules: ['@nuxtjs/axios'],
  // NOTE: I get the same errors if I leave this block out
  server: {
      host: '0.0.0.0',
      port: 3002
  },
  </code></pre>
  
  <p>When I deploy I use a <code>Dockerfile</code> that copies all the needed files from my project directory into the container, runs <code>yarn install</code>, exposes port 3002, runs <code>yarn build.prod</code>, and ends with <code>CMD ["yarn", "start"]</code> (see below for relevant <code>package.json</code> scripts).</p>
  
  <pre><code>"scripts": {
      "clean.nuxt": "rimraf .nuxt",
      "build.client": "nuxt build",
      "build.server": "tsc -p tsconfig.server.json", // Transpile TypeScript from `src/server` into `.nuxt/api`
      "build.prod": "run-s clean.nuxt build.client build.server",
      "start": "cross-env NODE_ENV=production node .nuxt/api/index.js",
  }
  </code></pre>
  
  <p>The docker image is built locally and pushed to an ECR repo. I then SSH into my server and run <code>docker-compose up -d</code> with this compose file:</p>
  
  <pre><code>version: '3.2'
  
  services:
    my_service:
    image: link/to/my/image:${TAG:-prod}
    container_name: my_container
    hostname: www.noticeeverythingcreative.com
    restart: unless-stopped
  
  ports:
    # Http Port
    - 3002:3002
  
  networks:
    - web-network # External (the actual compose file also has the corresponding networks block at the bottom)
  
  environment:
    - NODE_ENV=production
    - API_URL=https://www.noticeeverythingcreative.com
    - HOST=www.noticeeverythingcreative.com
    - PORT=3002
    - VIRTUAL_PORT=3002 
  </code></pre>
  
  <p>Here's my server-side controller that handles Nuxt rendering:</p>
  
  <p><strong>src/server/app/nuxt.controller.ts</strong></p>
  
  <pre><code>import { Controller, Get, Request, Response } from '@nestjs/common';
  import { join, resolve } from 'path';
  import * as config from 'config';
  
  const { Builder, Nuxt } = require('nuxt');
  const nuxtConfig = require(join(resolve(), 'nuxt.config.js'));
  
  @Controller()
  export class NuxtController
  {
      nuxt:any;
  
      constructor()
      {
          this.nuxt = new Nuxt(nuxtConfig);
          const Env = config as any;
  
          // Build only in dev mode
          if (Env.name === 'development')
          {
              const builder = new Builder(this.nuxt);
              builder.build();
          }
          else
          {
              this.nuxt.ready();
          }
  
      }
  
      @Get('*')
      async root(@Request() req:any, @Response() res:any)
      {
          if (this.nuxt)
          {
              return await this.nuxt.render(req, res);
          }
          else
          {
              res.send('Nuxt is disabled.');
          }
      }
  }
  </code></pre>
  
  <p>Here is the client-side contact component's <code>asyncData</code> and <code>head</code> implementations:</p>
  
  <pre><code>async asyncData(ctx:any)
  {
      // fetch page meta from API
      try
      {
          const meta = await ctx.$axios(&lt;any&gt;{
              method: 'post',
              url: `${ ctx.env.apiHost }/contact/meta`,
              headers: { 'Content-Type': 'application/json' }
          });
  
          return { meta: meta.data };
      }
      catch (error)
      {
          // Redirect to error page or 404 depending on server response
          console.log('ERR: ', error);
      }
  }
  
  head()
  {
      return this.$data.meta;
  }
  </code></pre>
  
  <p>The issues I'm having only occur in the production environment on the production host. Locally I can run <code>yarn build.prod &amp;&amp; cross-env NODE_ENV=development node .nuxt/api/index.js</code> and the app runs and renders without error. </p>
  
  <p><strong>Update</strong></p>
  
  <p>If I allow the Nuxt app to actually run on localhost inside the docker container, I end up with the opposite problem. For example, if I change my nuxt.config.js server and axios blocks to </p>
  
  <pre><code>server: {
      port: 3002, // default: 3000,
  },
  axios: {
      baseURL: 'http://localhost:3002'
  }
  </code></pre>
  
  <p>And change the request to:</p>
  
  <pre><code>const meta = await ctx.$axios(&lt;any&gt;{
      method: 'post',
      // NOTE: relative path here instead of the absolute path above
      url: `/api/contact/meta`,
      headers: { 'Content-Type': 'application/json' }
  });
  
  return { meta: meta.data };
  </code></pre>
  
  <p>A fresh load of <a href="https://www.noticeeverythingcreative.com/contact" rel="nofollow noreferrer">https://www.noticeeverythingcreative.com/contact</a> renders fine. This can be confirmed by viewing the page source and seeing that the title has been updated and that there are no console errors. However, if you load the home page (<a href="https://www.noticeeverythingcreative.com" rel="nofollow noreferrer">https://www.noticeeverythingcreative.com</a>) and click the contact link in the nav, you'll see <code>POST http://localhost:3002/api/contact/meta net::ERR_CONNECTION_REFUSED</code>. </p>
  
  <p>NOTE: this is the version that is deployed as of the last edit of this question.</p>