DEV Community

张桂雄
张桂雄

Posted on

From Product Manager to Indie Hacker: A 0-to-1 Survival Guide for Launching My Overseas Tool Website

Hi everyone, I'm a product manager. Recently, I took on a hardcore side project: independently developing and launching a pure, ad-free online web tool suite — Web Tools Hub (web-tools.tech).

The website has successfully run through the full-stack pipeline and is now indexed by Google. But the journey of pushing this project from my local machine to a production environment was paved with technical traps that nearly blew up my server. Today, I want to do a post-mortem and share why I built this site, as well as how I solved the bizarre DevOps headaches of deploying a Next.js app on a Baota (aaPanel) server.

1. Why build this web tool?

As a PM, I deal with various digital assets daily and frequently rely on mini-tools for image cropping, color inversion, format conversion, etc. However, most tool websites on the market share the same frustrating pain points:

  1. Ad Minefields: You have to dodge three fake "Download" buttons just to find the real one.
  2. Forced Logins: They force you to register an account or scan a QR code just to use a basic feature once.
  3. Privacy Risks: Many tools that could easily run locally in the browser force you to upload your files to unknown servers.

Driven by the hacker ethos of "building is better than buying," I decided to create a clean, lightweight, multi-lingual tool site myself. No flashy pop-ups, no tracking nonsense. Just a core philosophy: Ready to use, and leave when you're done.

2. The "Technical Pits" of Development and SEO

For the tech stack, I chose the highly popular Next.js. The developer experience was phenomenal, but when optimizing for SEO, I got completely stuck on a tiny sitemap.xml issue.

Pitfall Record: Sitemap formatting and i18n adaptation
To target an overseas audience, my site supports multi-language routing (i18n) for English, Spanish, Portuguese, etc. Initially, the Sitemap I generated kept throwing errors in the Google Search Console (GSC).

After diving deep into the documentation, I realized a standard Sitemap must use <urlset> as the root wrapper element, not <sitemapindex>. By dynamically generating URLs for all multi-language subpages within Next.js's app/sitemap.ts, and ensuring they were tagged with <lastmod> and <changefreq>, the Google bot finally recognized my 30+ pages.

3. The Life-or-Death Trials of Server Deployment

If writing code is like fighting regular mobs, server deployment is the boss fight. I used an Alibaba Cloud 2-core 2G lightweight server with the Baota Panel installed. Here are the three massive pits I stepped into:

Pit 1: Uploading node_modules directly to the server (Instant Crash)

Initially, I tried to take a shortcut by zipping my entire local project and overwriting it on the Linux server. As a result, the Node service crashed on the spot, throwing an invalid ELF header error.

💡 Survival Guide:
Next.js's underlying dependencies (like the sharp image compression library) are OS-specific! Transferring Mac/Windows compiled node_modules to Linux will absolutely break your app.
The correct, lightweight update flow:

  1. Run npm run build locally.
  2. Only zip the .next folder, public, package.json, and config files.
  3. Upload, unzip on the server, and run npm install --production in the terminal to pull Linux-compatible dependencies.
  4. Restart the Node project. Boom, online in seconds!

Pit 2: "Ghost Cache" (Code is updated, but the webpage is still old?)

After deploying a newly developed image tool, I excitedly opened the site only to find the old version! Even the XML Sitemap with the new routes hadn't changed.
I initially thought the deployment had failed, but I eventually found the mole: Baota Nginx's default static caching. Nginx would aggressively cache .xml, .css, and even pages for days at a time.

💡 The Cure:
Configure the HTTP headers in Next.js's next.config.ts to forcefully attach a "do not cache" seal to frequently updated files. After making this tweak, every subsequent update went live instantly and smoothly.

Pit 3: Disk suddenly hits 100% capacity, freezing the panel

One night, Alibaba Cloud sent a critical alert: my 40GB hard drive was at 94% capacity, memory was in the red, and I couldn't even load my Baota admin login page!

I connected via an SSH backdoor terminal, used the bt 14 command to rescue my panel login link, and ran du -sh /* | sort -hr to investigate. Wow! The /tmp folder in the root directory was hoarding a massive 13GB of data.
It turned out that an automated tool (OpenClaw) had encountered a loop error days prior and went crazy writing temporary .log files. Without regular cleanup, it literally bloated the server to death.

💡 Rescue Plan:
Dive into the /tmp directory, decisively delete those gigabyte-sized legacy temp logs (being extremely careful not to touch .sock system communication files), and crucially, empty the Baota recycle bin. Disk usage plummeted to 30%, and the server was fully revived!

4. Final Thoughts

Wrestling with servers, tweaking configs, clearing logs... while the process was full of nerve-wracking challenges, watching my website slowly pop up in Google search results and seeing the tools I envisioned running smoothly on a live server brings an unparalleled sense of accomplishment. That's the magic of building a product from 0 to 1.

My tool site, Web Tools Hub (web-tools.tech), is still actively iterating. From PM to indie developer, the journey continues. If you're also building your own projects, or if you've run into similar DevOps issues deploying Next.js, drop a comment below. Let's navigate these technical traps together!

Top comments (0)