没有不值得去解决的问题,也没有不值得去学习的技术!

A Tour of Go Production Public Network Acceptance Pitfalls: Switching From Cross-Border SOCKS Links to zgocloud direct

Figure 1: The old public network acceptance link repeatedly encountered curl 28 timeouts, ultimately causing the public-machine stage to fail

作者:

Recently, while continuing to add an Italian site to the A Tour of Go multilingual project, I ran into a fairly typical problem during the Production phase.

The site itself had been deployed successfully, the origin was healthy, and there were no issues with Cloudflare DNS. But once it came to public network acceptance, transient network failures caused the entire first Production process to abort.

At first, I thought simply adding more retries would fix it.

After investigating, the final adjustment turned out to be more fundamental:

I stopped routing full public network acceptance traffic through my local machine and the cross-border SOCKS link, and instead ran public network acceptance directly on zgocloud.

After the adjustment, all public network checks—including 105 sitemap URLs, CDN Cache, HTML Identity, and Socket Boundary—passed consistently.

1. The problem wasn’t a deployment failure, but a public network acceptance failure

The first Production of the A Tour of Go multilingual site isn’t just “service started, therefore success.”

The formal process also requires checking:

  • release identity
  • remote/source identity
  • key public routes
  • HTML identity
  • sitemap and all URLs within it
  • socket boundary
  • CDN Cache
  • browser automated acceptance
  • HUMAN visual gate

When the problem occurred this time, the earlier release and origin checks had actually already passed.

For example:

Plaintext
[verify-production] remote identity: PASS
[verify-production] source routes: 7/7 PASS

In other words, there was already evidence proving:

The current release was correct, and the origin service was healthy.

But once public network requests began, the same Cloudflare URL repeatedly hit 15-second timeouts:

Plaintext
curl: (28) Operation timed out after 15002 milliseconds with 0 bytes received
curl: (28) Operation timed out after 15002 milliseconds with 0 bytes received
curl: (28) Operation timed out after 15002 milliseconds with 0 bytes received

Ultimately:

Plaintext
[首次生产] FAILED
stage: public-machine
expected: command exit 0
actual: exit 1
Figure 1: The old public network acceptance link repeatedly encountered curl 28 timeouts, ultimately causing the public-machine stage to fail
Figure 1: The old public network acceptance link repeatedly encountered curl 28 timeouts, ultimately causing the public-machine stage to fail

This log is important.

If you only saw:

Plaintext
first-production FAILED

It would be easy to instinctively think you should redeploy, re-check Nginx, or even reconfigure Cloudflare DNS.

But the actual evidence doesn’t support those actions.

The failure occurred in:

Plaintext
stage: public-machine

Not in the deploy, source health, or DNS stages.

This means the right direction was to continue checking the public network acceptance link, rather than disrupting an already working Production environment.

2. The old public network acceptance link was a bit convoluted

The Production origin for this project is located in mainland China, while the Cloudflare control plane and some public network access require cross-border network transit.

To access Cloudflare reliably, I had already been using zgocloud as an overseas egress, handling relevant traffic via SSH, SOCKS, and similar methods.

But the old public network acceptance link was essentially still similar to:

Plaintext
本地电脑

跨境连接

zgocloud

Cloudflare

Production Origin

There’s an obvious problem here.

What actually needs to be verified is:

Plaintext
zgocloud → Cloudflare → Production

But a large amount of public network acceptance traffic still had to go through:

Plaintext
本地电脑 → zgocloud

This extra cross-border leg.

For an occasional page visit, this difference might not be noticeable.

But the Production verifier doesn’t just request the homepage once.

The current A Tour of Go Production sitemap contains a total of:

Plaintext
105 URLs

Beyond the sitemap, it also needs to check:

Plaintext
public routes
HTML identity
socket boundary
CDN cache

This means public network acceptance generates a large volume of consecutive requests.

As long as any leg of the cross-border link has some probability of jitter, the chance of failure scales up significantly as the number of requests increases.

At the time, besides curl 28 timeouts, I also encountered:

Plaintext
curl: (97) Failed to receive SOCKS response, proxy closed connection

Looking at any single failure in isolation, it might just seem like a sporadic occurrence.

But for formal Production acceptance, it can’t simply be ignored.

3. You can’t retry indefinitely just to make Production pass

Seeing transient network errors, a very natural thought is to add retries.

For example:

Plaintext
失败
→ retry
→ 还失败
→ 再 retry

But formal acceptance can’t turn into “just try a few more times, eventually one will pass.”

Otherwise, the credibility of automated acceptance will actually drop.

So this time, I reinforced a few principles.

1. Transient network errors allow bounded retry

For situations clearly attributable to transient network issues, the formal verifier can perform a limited number of bounded retries.

For example, the current verify-production.sh will apply this to some:

Plaintext
curl exit 6
curl exit 7
curl exit 16
curl exit 28
curl exit 35
curl exit 97

as well as some Cloudflare errors:

Plaintext
HTTP 522
HTTP 525

It performs a limited number of retries.

Currently, in verify-production.sh, a single logical public HTTP request will attempt at most 3 times.

However, one important caveat here:

3 is not a universal number used for all checks across the entire project.

Different stages have their own bounded retry or readiness rules depending on what is being checked.

For example, certain Nginx readiness or Playground Origin endpoint checks use different attempt counts.

What truly needs to be standardized isn’t “how many times everything retries,” but rather:

Retries must have clear boundaries.

2. After retries are exhausted, it must fail closed

No matter how many attempts a specific stage allows, once the formal bounded retries are exhausted, it must:

Plaintext
FAILED

You can’t keep assuming the network “should actually be fine.”

Nor can you skip failed checks just to let the first Production finish smoothly.

3. Stop immediately after a sitemap check failure

This is especially important for the current project.

The sitemap has:

Plaintext
105 URLs

Suppose that by the 20th URL, all bounded retries have failed; the remaining URLs haven’t actually been verified yet.

Continuing to request the 21st, 22nd… 105th URL at that point doesn’t change the fact that earlier ones already failed.

Therefore, the current formal logic is:

If a sitemap URL still fails after bounded retries, immediately fail closed.

Only after truly and completely verifying all URLs is it allowed to output:

Plaintext
sitemap: 105/105 PASS

This is also something I increasingly value:

The goal of automated acceptance isn’t to increase the PASS rate, but to make the PASS itself trustworthy.

4. The real adjustment: running public network acceptance directly on zgocloud

After further analysis, I felt that rather than continuously strengthening the local SOCKS link, it was better to rethink a more fundamental question:

Where exactly should Production public network acceptance run?

Since formal public traffic ultimately needs to access Cloudflare from overseas, the more direct path is actually:

Plaintext
zgocloud

Cloudflare

Production Origin

So the Production verifier now operates as:

Plaintext
本地维护机

    │ SSH

zgocloud

    │ 直接执行公网 HTTP 验收

Cloudflare

Production Origin

This means the logs now clearly show:

Plaintext
[verify-production] public network runner: zgocloud (direct)

The key here isn’t “switching to a different proxy.”

It’s:

Running the actual public HTTP acceptance from a more appropriate network location.

At the same time, not all checks were moved to zgocloud.

The local machine still handles formal release identity, and the remote Production source identity is still checked via its original formal path.

In other words, what was adjusted was:

Plaintext
public HTTP acceptance 的执行位置

rather than downgrading or bypassing:

Plaintext
release identity
source identity
Production authority

5. Why this is simpler than continuing to optimize SOCKS

In theory, I could have continued optimizing the original link:

Plaintext
本地
→ SOCKS
→ zgocloud
→ Cloudflare

For example, by continuing to implement:

  • more connection retries
  • more complex tunnel recovery
  • automatic SOCKS re-establishment
  • multi-egress switching
  • dynamic route scoring
  • automatic routing based on time of day

But for the current project, these solutions would become increasingly complex.

And the actual requirement was quite simple:

I need a relatively stable overseas network location to verify the real state Production presents to the public internet via Cloudflare.

Since zgocloud already exists, then:

Plaintext
直接在 zgocloud 执行公网 verifier

is clearly more direct than:

Plaintext
先从本地跨境连接到 zgocloud
再让大量请求经过这条 tunnel

This is why I didn’t continue with complex network engineering this time.

6. Actual Production results after the change

After the adjustment, I continued using the same formal it-IT release.

I didn’t republish or redeploy.

Once I re-entered formal Production acceptance, the output became:

Plaintext
[verify-production] public network runner: zgocloud (direct)
[verify-production] public routes: 7/7 PASS
[verify-production] html identity: PASS

sitemap URLs: 105/105
host mismatch: 0
HTTP failure: 0

[verify-production] sitemap: 105/105 PASS
[verify-production] socket boundary: PASS
[verify-production] CDN /: HIT -> HIT -> HIT PASS
[verify-production] CDN /tour/welcome/1: HIT -> HIT -> HIT PASS

PRODUCTION MACHINE ACCEPTANCE: PASS
[首次生产] 公网验收:PASS(31.1s)
Figure 2: After switching to zgocloud direct, all 105 sitemap URLs, CDN, and Socket Boundary checks passed
Figure 2: After switching to zgocloud direct, all 105 sitemap URLs, CDN, and Socket Boundary checks passed

This result forms a very stark contrast with the earlier failure logs.

Old approach:

Plaintext
source routes: PASS

公网请求 curl 28

public-machine FAILED

New approach:

Plaintext
zgocloud (direct)

public routes: 7/7 PASS

sitemap: 105/105 PASS

socket boundary: PASS

CDN: PASS

PRODUCTION MACHINE ACCEPTANCE: PASS

7. After a network failure, you shouldn’t just redeploy arbitrarily

This time there was also a very practical takeaway.

In the past, when encountering:

Plaintext
first-production FAILED

It was easy to feel an urge to:

Plaintext
是不是重新 deploy 一次比较保险?

But this actually depends on which stage the failure occurred in.

For example, this time:

Plaintext
source routes: PASS
remote identity: PASS

The Production service itself already had complete evidence proving it was healthy.

What actually failed was:

Plaintext
public-machine

And the errors were:

Plaintext
curl 28
curl 97

So the correct approach should be:

Plaintext
保留当前 release
保留 Production 现场

解决或等待网络条件恢复

正式 resume

rather than:

Plaintext
重新 publish
重新 upload
重新 deploy
重新修改 DNS

Otherwise, not only does it waste time, but it could also turn a simple network issue into a new deployment variable.

first-production now supports a formal resume and will re-check key identities.

So when encountering similar issues in the future, I will prioritize deciding based on:

Plaintext
stage
+
真实 evidence

to determine the path back, rather than starting over from scratch just because I saw FAILED.

8. Avoid peak cross-border network hours in the evening for first Production

The timing of this issue also led me to add a rule that’s more of an operational habit.

Unless there’s an urgent need:

Try to avoid peak cross-border network hours in the evening, Beijing time, for first Production, public network acceptance, and DNS/CDN activation.

I’m not trying to prove here that:

Plaintext
某个具体时间段一定会出现丢包

nor is there a need to set up complex long-term network monitoring for it.

It’s just that from a practical maintenance cost perspective:

If:

Plaintext
上午执行

and:

Plaintext
晚上执行

make no business difference, then there’s no need to proactively choose a time window that is more likely to introduce cross-border network variables.

Especially since first Production itself already involves:

Plaintext
DNS
Cloudflare
origin
shared assets
public acceptance
browser acceptance

There are already enough variables.

One less unknown is one less.

9. Direct reuse for adding new locales in the future

The A Tour of Go multilingual project now has several Production locales.

When adding new languages later, I don’t plan to redesign the network approach for each one.

The current formal path is reused directly:

Plaintext
Production deploy

direct-origin acceptance

Cloudflare DNS

minimal public readiness

zgocloud direct public machine acceptance

browser acceptance

HUMAN visual gate

first-production finalize

production_state=live

Transient network issues:

Plaintext
bounded retry

Retries exhausted:

Plaintext
fail closed

Production itself hasn’t changed:

Plaintext
保留现场
稍后正式 resume

rather than redeploying.

For subsequent locales, this part can already be directly reused as the Production baseline.

10. Summary

What I saw at the very beginning this time was actually just a few:

Plaintext
curl: (28)

and later:

Plaintext
curl: (97)

If I had only addressed the error codes themselves, it would have easily turned into:

Plaintext
再多重试几次
再把 timeout 调大一些

But the problem actually worth solving was:

Why must public network acceptance go through this longer, more volatile network path?

Ultimately, I didn’t keep stacking complex proxies, automatic routing, or multi-egress monitoring. Instead, I chose a simpler approach:

Plaintext
需要验证 Cloudflare 公网行为

就在 zgocloud 直接验证

while continuing to enforce:

Plaintext
bounded retry
+
fail closed
+
完整 identity 验证

This time also reaffirmed something for me:

Production acceptance itself is part of the Production architecture.

Where a site is deployed is one thing.

Where acceptance is executed from is another.

If the acceptance link itself is unstable, even if Production is completely healthy, you might constantly get false failures.

Rather than endlessly increasing retry counts, it’s better to first ensure:

Acceptance happens in a location that is reasonable, stable, and aligned with the actual verification target.

For the current project, zgocloud direct is already sufficient to solve this problem, and it’s simpler than continuing to maintain a complex cross-border SOCKS public network acceptance link.

系列导航

需要长期技术维护或远程问题排查?

我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。

如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:

  • ✅ PHP / Laravel / Yii2 老项目无人维护
  • ✅ Go / Gin 后端接口需要排查或优化
  • ✅ WordPress 网站访问慢、报错或插件冲突
  • ✅ Nginx / MySQL / Redis / Linux 服务器异常
  • ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
  • ✅ 需要长期远程技术支持或兼职维护

更多介绍请查看:关于我 & 合作

微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan