Search code examples
node.jsexpressdockerprerender

Node Prerender Working on First Page Load - 500 Error on Subsequent Loads


You can verify that this is the case. Click the link, let it load, then refresh: http://www.justinmcmahon.com/?_escaped_fragment_=

Probably of significance: my app is running in a docker container on port 3000, as is the prerender server (on port 9000), both of which are running behind the official Nginx docker image.

Also maybe of significance: The top level domain has a .htaccess redirect to the www subdomain, which points to an AWS elastic IP. I'm not very smart at this yet, so that's the best way I've come up with so far to point things in the right direction.

.htaccess redirect

RewriteEngine on 
RewriteRule ^(.*)$ http://www.justinmcmahon.com/$1 [R=301,L] 

Nginx docker-compose.yml:

nginx:

 build: .
 container_name: Nginx
 hostname: nginx
 restart: always

 environment:
   - DEFAULT_HOST=www.justinmcmahon.com

 volumes:
   - /var/run/docker.sock:/tmp/docker.sock:ro

 ports:
   - 80:80
   - 443:443
   - 5984:5984 

Prerender Dockerfile

FROM node:5.2.0
ENV NPM_CONFIG_PRODUCTION=true
ENV NODE_ENV=production
COPY dist /app
WORKDIR /app
RUN npm install
EXPOSE 9000
CMD ["node", "server"]

I have the following at the top of my Express config:

app.use(require('prerender-node').set('prerenderServiceUrl', config.PRERENDER_SERVICE_URL));

Docker logs for the prerender container show a 304 status, but Express is throwing a 500


Solution

  • I found a solution that seems to solve the problem, but I don't love it because I'm not sure what unintended consequences it might have.

    In /server.js I defaulted the PRERENDER_NUM_WORKERS and PRERENDER_NUM_ITERATIONS to 1 and uncommented the inMemoryHtmlCache()

    #!/usr/bin/env node
    var prerender = require('./lib');
    
    var server = prerender({
        workers: process.env.PRERENDER_NUM_WORKERS || 1,
        iterations: process.env.PRERENDER_NUM_ITERATIONS || 1
    });
    
    
    server.use(prerender.sendPrerenderHeader());
    // server.use(prerender.basicAuth());
    // server.use(prerender.whitelist());
    server.use(prerender.blacklist());
    // server.use(prerender.logger());
    server.use(prerender.removeScriptTags());
    server.use(prerender.httpHeaders());
    server.use(prerender.inMemoryHtmlCache());
    // server.use(prerender.s3HtmlCache());
    
    server.start();
    

    I'm open to a better answer, or at least assurance that this is an acceptable solution, and maybe an explanation as to why.