HeQihan

HeQihan

Blog Frontend Shiro Low Memory Deployment ✨

The day before yesterday at around six o'clock, my blog server crashed. Although Alibaba Cloud sent me an alert, it was of no use. While I was casually browsing my 2C2G3M territory on the internet, I found that only the homepage was accessible, while other pages displayed a 504 Gateway Timeout. After checking Alibaba Cloud's monitoring, it turned out to be a memory leak; the memory was maxed out. I wanted to see which culprit was responsible, but I couldn't connect via SSH anymore.

This was no ordinary failure; I had to take strong measures to reclaim my 2C usable 0G3M territory.

After a forced restart, memory usage decreased, just in time for me to update both the front and back ends of my blog. My deployment referenced JiuYue's tutorial, specifically this and this. Of course, I was using a partial version, but as long as it worked, that was fine.

Updating the backend with Docker was quite simple, no need to elaborate. In short, the upgrade was completed smoothly. Updating the front end was not as easy; the build required a considerable amount of memory. Last time, I rented a sufficiently large machine from Alibaba Cloud on a pay-as-you-go basis and transferred everything over the internal network. Unfortunately, times have changed, and I now have a local Ubuntu backup machine, so there was no need to boost Alibaba's morale.

The reality is somewhat regrettable. If I were to transfer everything at once, the external 3M bandwidth would still be insufficient, especially considering my upload speed is quite disappointing. Would I repeat the same mistake?

It is recommended to read Mix-Space Deploy Latest Frontend Shiro before reading the following content.


Thanks to the advanced features of Next.js used in the Shiro project, I flipped through the project's next.config.mjs and found that it was configured with output: 'standalone'! This is exactly the powerful tool I need! After next build, it intelligently packages only the truly necessary dependency files (even a "slim version" of node_modules), and then stuffs everything into the .next/standalone directory, resulting in a super mini build package!

Win

// The next.config.mjs in the project looks like this:
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'standalone', // It's this line!
  // ... other configurations
};
export default nextConfig;

The project also has a packaging script that can automate the packaging of the standalone mode output for direct deployment.

Win win

#!env bash
set -e
CWD=$(pwd)

cd .next # Enter the build output directory
rm -rf cache # Clean up build cache
cp -r ../public ./standalone/public # Copy public static resources to standalone directory

cd ./standalone # Enter standalone directory
echo ';process.title = "Shiro (NextJS)"' >>server.js # Add process title
mv ../static/ ./.next/static # Move essential static resources for the server (for standalone server use)
cp $CWD/ecosystem.standalone.config.cjs ./ecosystem.config.js # Copy PM2 configuration file

cd .. # Return to .next directory
mkdir -p $CWD/assets
rm -rf $CWD/assets/release.zip
zip --symlinks -r $CWD/assets/release.zip ./* # Compress the entire prepared .next folder

The script takes the optimized standalone output, adds the PM2 configuration and static resources as "ingredients," and finally produces a compressed package assets/release.zip for easy transfer and deployment.

Win win win

The theory is feasible; next comes the practical operation.

What to do on the development machine#

First, install pnpm, then run the following in the project root directory:

pnpm install # or pnpm i
pnpm build

At this point, next build will run, generating the .next folder, which contains our long-awaited .next/standalone.

Then run:

bash standalone-bundle.sh

This will produce a deployment package assets/release.zip. 🥳

Finally, send this compressed package to the server, and the task of the development machine can be considered complete.

What to do on the server#

First, ensure you have the appropriate version of node.js and PM2, and grant the necessary permissions.

sudo mkdir -p /srv/shiro-app
sudo chown -R user:usergroup /srv/shiro-app # Grant yourself permissions
cd /srv/shiro-app
sudo unzip /path/to/compressed/package/release.zip

Then, enter the standalone directory, where both server.js and ecosystem.config.js are located.

cd standalone
pm2 start ecosystem.config.js

Now, everything is successfully completed. However, during the previous deployment, there were constant errors, and after a long investigation, I discovered that I had written the domain name incorrectly in .env. What a major failure.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.