I Got Rejected by 3 Cloud Providers. My Laptop Didn't Care.
I Got Rejected by 3 Cloud Providers. My Laptop Didn’t Care.
我被三家云服务商拒之门外,但我的笔记本电脑毫不在意。
I needed to host a real client’s CMS site. For free. That last part turned out to be the hard bit. I’d built a modular, English-native Laravel CMS after switching off a Persian-language open-source project that needed more translation work than I had appetite for. Once the app was running cleanly in Docker locally, deployment seemed like the easy part. It was not. 我需要为一个真实客户托管一个 CMS 网站,而且必须是免费的。最后这一点成了最难的部分。我放弃了一个波斯语开源项目(因为翻译工作量超出了我的承受范围),转而构建了一个模块化的、原生英语的 Laravel CMS。当应用程序在本地 Docker 中顺利运行后,我以为部署会很简单。事实并非如此。
Round 1: Oracle Cloud Oracle’s Always Free tier is genuinely the best deal in cloud hosting, 4 ARM cores, 24GB RAM, forever, for free. The catch: their identity verification is aggressive about rejecting virtual and prepaid cards, which is exactly the kind of card a lot of us outside the US/EU actually have access to. Rejected. 第一轮:Oracle Cloud Oracle 的“永久免费”套餐确实是云托管领域最划算的方案:4 核 ARM 处理器、24GB 内存,永久免费。但问题在于:他们的身份验证机制对虚拟卡和预付卡非常排斥,而这恰恰是我们许多身处欧美之外的用户最常使用的支付方式。结果:被拒。
Round 2: Hetzner Cheap, reputable, well-documented. I tried creating an account to run alongside Laravel Forge. Account rejected, no real explanation given, which I’ve since learned isn’t unusual for accounts from certain regions without an existing payment history. 第二轮:Hetzner 价格便宜、信誉良好、文档齐全。我尝试创建一个账户以便配合 Laravel Forge 使用。账户被拒,没有给出任何实质性解释。后来我了解到,对于某些地区且没有既往支付记录的账户来说,这种情况并不罕见。
Round 3: Cloudways
This one actually worked. Managed PHP hosting, full SSH access, Laravel officially supported. I spent real hours getting it production-ready: chasing down a Redis ACL permission error that took four separate diagnostic passes to understand, discovering two leftover files from the original composer create-project scaffold that were silently colliding with TypiCMS’s own migrations, and fixing an SSL certificate that had been issued for the wrong hostname. I got it fully working. Then the free trial ended.
第三轮:Cloudways
这一家确实成功了。托管式 PHP 主机、完整的 SSH 访问权限,且官方支持 Laravel。我花了数小时将其配置到生产环境:排查了一个 Redis ACL 权限错误(耗费了四次诊断才搞清楚原因),发现了两个来自原始 composer create-project 脚手架的残留文件,它们与 TypiCMS 自身的迁移脚本产生了静默冲突,我还修复了一个签发给错误主机名的 SSL 证书。一切终于正常运行了。然后,免费试用期结束了。
The realization At some point, staring at a third rejected and expired hosting option, I asked myself the obvious question I’d been avoiding: my Docker setup already runs perfectly on my own machine. Why does it need to run somewhere else at all? 顿悟 在盯着第三个被拒或过期的托管方案时,我问了自己一个一直回避的显而易见的问题:我的 Docker 环境已经在自己的机器上完美运行了。为什么非要把它放到别的地方去运行呢?
The two things standing between “runs on my laptop” and “reachable by anyone on the internet” turned out to be smaller problems than I’d assumed: My laptop has no public address. It sits behind my home router like everyone’s does. Getting a real domain with HTTPS usually means server config I didn’t want to hand-roll. Cloudflare Tunnel solves both. It opens a secure, outbound-only connection from your machine to Cloudflare’s edge, no inbound ports, no router configuration, works fine even behind CGNAT. Anyone visiting your domain talks to Cloudflare, which quietly forwards the conversation through the tunnel to your laptop. Free, automatic HTTPS comes along with it. Twenty minutes later, my domain was live, served from the same laptop I was debugging it on. 阻碍“在笔记本上运行”到“互联网上任何人都能访问”之间的两件事,其实比我想象的要简单: 我的笔记本没有公网 IP,像大多数人一样位于家用路由器之后。 获取一个带有 HTTPS 的真实域名通常需要复杂的服务器配置,而我不想手动折腾。 Cloudflare Tunnel 同时解决了这两个问题。它从你的机器到 Cloudflare 的边缘节点建立了一条安全的、仅限出站的连接,无需开放入站端口,无需配置路由器,即使在 CGNAT(运营商级 NAT)环境下也能正常工作。任何访问你域名的人都会先连接到 Cloudflare,由它通过隧道将流量转发到你的笔记本。同时还附带了免费的自动 HTTPS。二十分钟后,我的域名上线了,服务正是由我调试代码的那台笔记本提供的。
The honest tradeoff This isn’t real production hosting, and I won’t pretend otherwise. The site is only reachable while my laptop is on and connected. If I close the lid, the site goes down. That’s a genuinely different reliability story than a VPS. But for a client demo, a side project, or a real site while the client sorts out the an actual hosting budget, “free and mostly-always-up” beats “rejected everywhere I tried.” 坦诚的权衡 这并不是真正的生产级托管,我不会假装它是。网站只有在我的笔记本开机并联网时才能访问。如果我合上盖子,网站就会下线。这与 VPS 的可靠性完全不同。但对于客户演示、个人项目,或者在客户落实正式托管预算期间的过渡网站来说,“免费且基本在线”远胜于“到处被拒”。
What I actually hit setting it up
A few things worth knowing if you try this yourself:
Mixed content / broken CSS. Cloudflare terminates HTTPS at their edge and forwards plain HTTP to your machine internally. Most frameworks don’t know this and will generate broken http:// asset links unless you explicitly tell them to trust the proxy. In Laravel, that’s one line: URL::forceScheme('https'); in your AppServiceProvider.
Containers don’t survive a reboot by default. Docker itself restarting on boot doesn’t mean your containers come back with it, every service in your docker-compose.yml needs restart: unless-stopped explicitly, or a reboot leaves your “working” setup silently dead.
cloudflared service install looks for its config in a specific place (/etc/cloudflared/config.yml), not wherever you happened to create your tunnel from, an easy, non-obvious thing to trip over the first time.
配置过程中遇到的坑
如果你打算尝试,有几点值得注意:
混合内容/CSS 损坏。Cloudflare 在边缘节点终止 HTTPS,并在内部向你的机器转发纯 HTTP。大多数框架对此并不知情,会生成错误的 http:// 资源链接,除非你明确告诉它们信任代理。在 Laravel 中,只需在 AppServiceProvider 中添加一行代码:URL::forceScheme('https');。
容器默认不会在重启后自动恢复。Docker 本身随系统启动并不意味着你的容器也会随之启动,每个 docker-compose.yml 中的服务都需要显式设置 restart: unless-stopped,否则重启后你的“工作环境”会静默失效。
cloudflared 服务安装程序会在特定位置(/etc/cloudflared/config.yml)查找配置文件,而不是在你创建隧道的目录中。这是第一次尝试时很容易踩到的坑。
I packaged it up Since I’d already worked through all of this the hard way, I turned it into a small, reusable, MIT-licensed toolkit: selfhost-tunnel-kit. It’s an interactive script that automates the whole setup (install cloudflared, authenticate, create the tunnel, route DNS, install it as a persistent service), plus docs covering exactly the issues i have said above, written generically enough to apply whether you’re running Laravel, Django, Express, or anything else in Docker. If you’ve been putting off shipping something because every “free” cloud tier somehow isn’t free for you either, try pointing a domain at your own machine instead. It works better than it has any right to. 我将其打包成了工具 既然我已经通过“硬核”方式解决了所有问题,我将其整理成了一个小巧、可复用且基于 MIT 协议的工具包:selfhost-tunnel-kit。这是一个交互式脚本,可以自动化整个设置过程(安装 cloudflared、身份验证、创建隧道、路由 DNS、安装为持久化服务),并附带了涵盖上述所有问题的文档。这些文档编写得足够通用,无论你运行的是 Laravel、Django、Express 还是 Docker 中的其他任何东西,都适用。如果你因为每个“免费”云层对你来说都不免费而迟迟无法发布项目,不妨尝试将域名指向你自己的机器。它的效果好得超乎你的想象。