LoudNoises logo

Export your Next.js site without DDOSing yourself

Cover Image for Export your Next.js site without DDOSing yourself
Posted: under Next.js,React
Reading time: 3 min read

This blog post is over two years old and the underlying methods may have changed. We maintain it publicly only for archival purposes, and in case you have a legacy code need.

Here was our situation as we approached launch of a recent Next.js-powered large content website. We were about 3 weeks away from launch and wanted to start the production server setup, testing deployment, exports, etc.

Everything was running smoothly until we got to the Next.js static exports part of the deployment. Thus far in the project, our team had always been running static export tests from their local dev machines which were some physical distance away from the production server. Sufficiently far that the dev machines were unlikely to overload the production server (the location of the API for the project).

If you are still trying to get static exports setup on your project, check out our detailed post on the WPGraphQL blog.

Everyone's favorite error: 502

Nearly as soon as we fired off the export from the same server as the API, our terminals filled with 502 errors, specifically:

Error while running `getMarkupFromTree` { Error: Network error: Unexpected token < in JSON at position 0
    at new ApolloError (/var/www/next/node_modules/apollo-boost/node_modules/apollo-client/bundle.umd.js:92:26)
    at /var/www/next/node_modules/apollo-boost/node_modules/apollo-client/bundle.umd.js:1581:34
    at /var/www/next/node_modules/apollo-boost/node_modules/apollo-client/bundle.umd.js:2001:15
    at Set.forEach (<anonymous>)
    at /var/www/next/node_modules/apollo-boost/node_modules/apollo-client/bundle.umd.js:1999:26
    at Map.forEach (<anonymous>)
    at QueryManager.broadcastQueries (/var/www/next/node_modules/apollo-boost/node_modules/apollo-client/bundle.umd.js:1997:20)
    at /var/www/next/node_modules/apollo-boost/node_modules/apollo-client/bundle.umd.js:1476:29
    at <anonymous>
    at process._tickDomainCallback (internal/process/next_tick.js:228:7)
  graphQLErrors: [],
   { ServerParseError: Unexpected token < in JSON at position 0
    at JSON.parse (<anonymous>)
    at /var/www/next/node_modules/apollo-link-http-common/lib/index.js:35:25
    at <anonymous>
    at process._tickDomainCallback (internal/process/next_tick.js:228:7)
     name: 'ServerParseError',
      Response {
        size: 0,
        timeout: 0,
        [Symbol(Body internals)]: [Object],
        [Symbol(Response internals)]: [Object] },
     statusCode: 502,
     bodyText: '<html>\r\n<head><title>502 Bad Gateway</title></head>\r\n<body bgcolor="white">\r\n<center><h1>502 Bad Gateway</h1></center>\r\n<hr><center>nginx/1.10.3 (Ubuntu)</center>\r\n</body>\r\n</html>\r\n' },
  message: 'Network error: Unexpected token < in JSON at position 0',
  extraInfo: undefined }

This was a WPGraphQL (our review) API, running from a Wordpress site. If you've been building Wordpress sites at substantial scale for some time, you can probably guess the error we got from PHP:

[error] 1248#1248: *5807411 connect() to unix:/run/php/php7.0-fpm.sock failed (11: Resource temporarily unavailable) while connecting to upstream, client: xxx.xxx.xxx.xxx, server: website.com, request: "GET /this/page HTTP/1.1", upstream: "fastcgi://unix:/run/php/php7.0-fpm.sock:", host: "www.website.com"

If you have run in to a 502 error on a Wordpress site, you also know that your day was just ruined. There are a near infinite number of causes to which this error could refer.

De-DDOS yourself

It became clear after some discussion with @p-k on Spectrum (ht for the excellent sleuthing on this), that the issue here is that Next.js export process runs on multiple threads, and due to the proximity of the applications and the speed of execution, you essentially DDOS yourself every time you export your site.

Since we plan to export several times a day as the site contents are updated, this would obviously have been a non-starter. This is also the reason why we don't build the site locally and simply deploy the exported site to production.

So, we need to tell Next.js to run on fewer threads and with lower concurrency in order to successfully build this site on the production server.

Easy enough: update your package.json file, specifically the export script to include the --threads and --concurrency options, for example:

  "scripts": {
    "export": "next export --threads 1 --concurrency 1",

This should solve the issue, but will mean much slower export times. Ours went from about 10-12 minutes to about 60 minutes. Further testing will help us determine what the API can handle in terms of additional threads and higher concurrency. In the mean time, this still accomplishes our goal of multiple builds per day.

Check out the next post in our series on building static Next.js sites, Next.js + Multiple Apollo Clients & GraphQL Sources

Let's talk. We can help grow your business.

Your company is already off to a running start and you are ready for some serious growth. You're seeking the right web technology partner to propel your business forward. You've come to the right place.

Tell us a bit about your business.