ASP.NET Core Docker OCR 網站免費上線可行嗎?實測 6 個雲端平台
最近(2022年8月)資訊界有一個重磅新聞 Heroku's Next Chapter,知名的雲端平台 Heroku 將終止部分服務的免費使用額度,原因說是因為免費產品計劃遭到各種濫用,本來免費的,以後要變成每個月約 7~15 美元起跳,太久沒登入的帳號也會被關掉。
我的 Heroku 帳號最早是 2015 年註冊的,嚇得我趕快去登入看一下,登進去之後裡面都是一堆警告訊息,以前的測試程式環境過了沒幾年就 end of life,或是 build failed 的錯誤訊息。
其實後來都沒在用。當初會認識這個平台純粹是衝著有免費服務,而且有些網路教學範例程式有 Deploy to Heroku 的功能(如下圖)

Heroku 這個服務在 2010 年被知名 CRM 廠商 Salesforce 收購,從此頭銜變成「Salesforce 旗下的 Heroku」,後續的商業發展可以看看這兩篇
前幾天才寫一篇甲骨文 Oracle Cloud 自動掛機搶免費VM (Windows/Ubuntu設定方式),排了一個多禮拜還沒搶到。之前也寫過 Open Shift 的網站放在 PaaS 第一次被都更就上手,Open Shift 現在已經改版改到不知道該從何用起,也只剩註冊後前幾天免費了。
想不到才過沒幾天又碰到要讓大家找地方搬家的事情了。
在一些人哀鴻遍野,討論要搬到哪邊去的時候,看了一下大家提的替代服務,挑幾個「可以跑 server side (後端)程式的」出來試用分享一下。
這篇原本寫在 Heroku 取消免費方案的時間點(2022 年),幾年後這類 PaaS 服務已經很少能用「永久免費」四個字概括:
- Fly.io 在 2024 年底正式取消免費方案,新帳號只有 $5 試用額度
- Render 仍有 Free Web Service,但 15 分鐘沒有流量就會 spin down
- Railway 有 $5 試用額度與 Hobby plan
其他大部分免費平台的計費方式,也多半是設計成等豬養肥了再殺。例如萬一網站突然爆紅,就準備收到天價帳單,或是服務直接被停止,要付錢才能把資料贖回去。
如果是自己業餘玩玩還好,如果是商業接案上有各種條款跟限制的,才不會挑這種成本和穩定性難以預估的雲端服務來用哩。
AI 寫好程式了,但 localhost:3000 怎麼讓別人打開?
因為 localhost 只是你的電腦內部網址,除非把網站放到一台公開主機上,否則其他人永遠無法連線。本文後面介紹的 Fly.io、Render、Railway、Cloud Run 等平台,都是解決這個問題的方法。
到了 2025~2026 年,這個問題又多了一批新的受眾——不是傳統意義上的工程師,而是靠 AI 工具(ChatGPT、Claude、Google AI Studio...)邊學邊做、一天就做出一個什麼代購訂單管理還是訂餐系統的人。
AI vibe coding 盛行之後,有一大群人面對的問題不是怎麼寫程式,而是「我的 localhost:3000 功能都正常,怎麼讓別人也能打開這個網址?」這是一個完全不同性質的問題,但答案需要用到的基礎設施其實跟本文高度重疊。
如果需求是「讓 AI 生出來的網站可以公開分享」,而不一定要跑後端 API 或資料庫,有幾個選項更快:
- Firebase Hosting 可以把靜態或搭配 Cloud Functions 的應用程式部署上去
- Lovable 直接在平台上 AI 生成 React 應用程式,按一個按鈕就能發佈成公開網址
- Manus 生成出來的 app 直接跑在 Manus 的雲端環境裡、身分控管還可以直接用 Manus 帳號登入,不用考慮任何部署或登入功能沒寫好的問題。
- Figma Sites,如果是做 UI 設計或視覺出身、想把網站快速上線的,也可以參考這篇站內文章:Figma Sites 試用心得,Figma 直接從設計稿發佈成網站,完全不需要碰任何 Dockerfile 或 CI/CD 設定。
這些工具的共同特色是:完全不需要自己研究 Docker、container、port 對應、環境變數這些事情,平台幫大家打理好了。但大家也最好不要產生平台功能範圍外的需求,人家的商業模式沒有要 100% 照顧每個人的所有需求,太多天馬行空的想法只能換其他平台。
本文後面要講的,是正常的工程師的那條路——程式比較複雜、需要後端邏輯、需要自己決定怎麼部署的情境。
測試程式: ASP.NET Core + Docker 的組合
核心問題是:同一份程式配上 Dockerfile,能不能在這些 PaaS 上直接跑起來?
一開始看那幾個平台都有支援 Python, GO, RoR 等一些程式語言,但都沒寫說支援 ASP.NET Core。
於是某個周末下午臨時起意,那試一下 Docker 容器技術,把 .NET Core 的程式配上 Dockerfile,能否正常執行?藉機看看「.NET 跨平台好棒、容器化好棒」,是一堆在完美環境寫程式的高手自己在講,還是真的要用的時候一堆地雷?
.NET Core 跟傳統 .NET Framework 有什麼不同?
這裡先說一下,因為搞錯會影響能不能用這些 PaaS。
傳統的 .NET Framework(就是那個 3.5、4.5、4.8 的版本)只能跑在 Windows 上。如果在 Visual Studio 建一個 ASP.NET WebForms 或 MVC 5 的專案,丟到任何 Linux 容器平台,一定跑不起來——那些平台的底層機器是 Linux,沒有 Windows 授權、也沒有 IIS。
.NET Core(現在統稱 .NET,從 .NET 5 開始就叫這個名字)的最大賣點就是跨平台:同一份程式,在 Windows 開發、在 Linux Docker 容器裡跑、在 macOS 測試,理論上都可以。本文的測試程式就是走這條路。
另外值得一提的是 Minimal API,傳統的 ASP.NET MVC 或 Web API 專案,建完之後就是一堆 Controller、Startup.cs、各種設定檔,跑起來的 image 也比較大。
.NET 6 以後的 Minimal API 可以把一個簡單的 API 壓縮到幾十行,Program.cs 寫完就好,除了很適合那種前後端完全分離成不同站台的,還很適合本文這種部署測試用途:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/ping", () => "pong");
app.MapPost("/ocr", async (OcrRequest req) => {
// 呼叫 Google Vision API
return Results.Ok(new { text = result });
});
app.Run();
比起舊式寫法,這種方式更容易搞清楚程式跟容器之間的關係,不用在一層又一層的程式架構裡大海撈針。
.NET 版本要選哪個?
本文最初測試時用的是 .NET 6 (已在 2024 年 11 月結束支援)。現在新專案建議選 .NET 8 LTS。
Dockerfile 裡的 base image 對應改成:
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
ENV ASPNETCORE_URLS=http://0.0.0.0:8080
EXPOSE 8080
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM base AS final
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "YourApp.dll"]
如果 Dockerfile 裡還寫死 .NET 6 image,今天可能還能 build,但套件漏洞掃描、平台預設 build image、NuGet 套件相依性都可能開始出怪問題,與其等線上部署失敗,不如更新到仍在支援期內的 LTS。
如果用 Visual Studio 做開發:
- 要更新到 2022 才可以開發 .NET 8
- 只要新建置專案時把「啟用 Docker」勾起來(要選 Linux 版),就會自動產生 Dockerfile 和對應的程式碼
- 在本機 dotnet run 的時候也會看到 Docker 裡面自動生好對應的 image 和執行中的 container。
這裡值得補充一個觀念:本文的測試方式是「自己寫 Dockerfile,然後推到各個平台」,但不是所有平台都要這樣做。
以本文介紹的幾個平台來說,Render、Railway 都支援另一條路: 把程式碼放在 GitHub 之類的程式碼管理工具,平台自動偵測專案用的技術,在雲端自動跑 build、打包、部署,全程不需要自己寫 Dockerfile,也不需要研究 container 怎麼設定。
這個流程通常叫做 CI/CD(持續整合 / 持續部署):每次 push 程式碼,平台就自動跑一遍,新版本就上線了。對不熟悉 Docker 的人來說,這條路阻力小很多;缺點是平台預設的環境,細節沒辦法像自己寫 Dockerfile 那樣控制。
本文因為程式需要用到 Puppeteer(需要在 Linux 容器內安裝 Chrome)、調整時區和語言環境等比較特殊的需求,才選擇了自己寫 Dockerfile 的方式,而不是無腦把程式碼直接丟上去。
以下介紹測試程式的幾個功能:
OCR 功能的 API
傳入圖片 URL 和一些驗證參數,把辨識結果用 json 格式回傳。主要測試 CORS 設定,和輸入與輸出資訊的程式判斷。
影像文字辨識使用 GCP 的 Google.Cloud.Vision API,這功能每月前 1,000 次免費,超過才收費。程式實作與 nuget 要裝哪些套件,參考官方文件範例 Detect text in a single image。帳號綁定使用 Service account 的驗證方式設了一組 GOOGLE_APPLICATION_CREDENTIALS。另外碰到 We can not access the URL currently 的奇怪錯誤訊息,改把圖片轉成 base64 再去辨識。
測試資料庫連線
那些服務本身也有雲端代管資料庫,但是通常很貴,不敢用,先用其他外網的 MySQL & SQL Server 資料庫,測試連線跟基本的查詢,看看資料庫能否正常 CRUD。
資料庫的連線字串沒有直接寫死在程式或 appsettings.json 裡面,而是用 Docker env 的功能從外部植入,各家平台要怎麼把 docker env 設定上去,又是一番花時間的測試過程。
從幣安的 API 抓 ETHUSDT 的價錢
顯示現在幾點幾分的價格是多少、近 24 小時最高與最低,API 會用到這兩支:
- https://api.binance.com/api/v3/ticker/24hr?symbol=ETHUSDT
- https://api.binance.com/api/v1/ticker/price?symbol=ETHUSDT
主要是測試主機時間、Decimal 計算、HttpWebRequest 的功能。
果然發現一個丟到線上才會發現的問題,因為那些系統平台都不是台灣時區,所以要在 Dockerfile 裡面加兩行參數改成 Asia/Taipei 的時區,網頁上用來計算跟顯示的時間才會正確。
ENV 的寫法格式錯一點就沒效,container 根本讀不到,時區還是 UTC。
(X) ENV TZ = "Asia/Taipei"(等號有空格)
(X) ENV TZ = Asia / Taipei(斜線有空格)
(O) ENV TZ=Asia/Taipei
而且最好搭配一行 RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime 確保系統層也生效,否則光設環境變數,部分 library 還是讀不到正確時區。
使用 C# 版的 Puppeteer 爬資料跟存檔
在之前的文章有嘗試過用 npm 版的 Puppeteer,這次用 NuGet 上的 PuppeteerSharp 套件重做一個類似的功能。
Puppeteer 的機制是在專案資料夾直接裝一套網頁瀏覽器,換在 Docker 內執行之後,容器不是完整版作業系統,當然不可能呼叫 Host OS 的瀏覽器,要改寫 Dockerfile 增加一段下載瀏覽器的,程式內宣告 Puppeteer 時使用的參數也要調整,才能正常執行。
承第 3 點的時區問題,這邊也發生意外:碰到要爬的網頁封鎖國外 IP 的,當然打不開;
如果開 Google 或某些網頁,抓到的網頁會是德語或其他語言的,
這個後來怎麼改 Dockerfile 都沒有改成功,
還有的平台就是跑不起來這種 headless browser。
讓 Chrome 可以在容器裡跑,需要在 Dockerfile 裡另外安裝 google-chrome-stable 和一批 font 套件,這讓整個 Docker image 膨脹到相當可觀的大小,build 一次的時間也會拉很長,這是使用 Puppeteer 的固定成本。
跑不起來的原因通常是平台的容器沙箱限制了 Chrome 需要的某些 Linux kernel 功能(--no-sandbox 參數要不要加、/dev/shm 的大小夠不夠),不是純粹設定問題,有些平台硬體環境直接不支援。
至於爬到德語的問題:Dockerfile 裡雖然設了語言環境的環境變數,但 Chrome headless 的語言不是靠 locale 決定的,而是靠 Accept-Language header 或 Chrome 啟動參數。環境變數設好不代表 Chrome 發出的 HTTP request 也跟著改語言,要另外在程式碼層調整啟動參數才有效。
讀檔與寫檔
將上述部分步驟的執行結果存在一個資料夾內,並另外做一個顯示檔案清單與檔案內容的頁面。程式執行之後建立資料夾、建立檔案、讀取檔案、產生公開檔案路徑,這幾件事在傳統網頁系統架構下沒什麼特別的,但這又讓我花了不少時間。
關於讀檔寫檔碰到的問題,以及 Docker 為什麼重新部署會讓檔案消失,這又牽涉到 Docker 的一個特殊設計
Docker 的邏輯是:一個 container 就像一次性的乾淨環境。程式碼更新時,舊 container 刪掉、新的重建,裡面的資料一起清空。在程式裡寫入磁碟的東西(上傳的圖片、log、使用者產生的檔案),不掛 Volume 的話每次 deploy 都會歸零。
每個平台都有提供 Persistent Volume 之類的功能,但設定方式都不太一樣:
- 有的是要在專案裡另外增加專屬的 yaml/toml 檔案
- 有的是要在平台網頁 UI 上操作,然後有些按鈕是鎖住的,要拿魔法小卡出來刷。
因為 ASP.NET Core Web 專案內有一個 wwwroot 的目錄,實際網頁瀏覽時不會有這層,各家在指定掛載磁碟的路徑輸入方式也都不一樣,要花時間測試設定 > 寫檔 > 重新 deploy > 檢查檔案還在不在。
實務上分兩種情況處理:
- 暫存檔、log:清空就清空,正常情況本來就不該長久留在 container 裡,送到 stdout 或外部 logging 服務就好。
- 使用者上傳的圖片、業務用的資料:一定要掛 Persistent Volume,或直接存到外部物件儲存(S3、GCS、Cloudflare R2)。把檔案存在本機磁碟又不掛 Volume,等於把客戶資料放在隨時會蒸發的空間。
決定掛載路徑前,先弄清楚你的程式實際寫入的是哪個路徑(wwwroot、/app/uploads,還是其他地方),才不會 Volume 掛好了、但程式還是寫到沒被掛到的目錄。後面各章節有各平台個別的設定說明。
Docker Compose 在 PaaS 上好用嗎?
本機開發很好用,但不要把它當成所有 PaaS 都能直接吃的部署格式。
Compose 很適合本機開發、整合測試、把 web + db + redis + worker 的關係寫清楚;到了 PaaS 上,通常會被拆成多個服務、環境變數、Volume、Private Networking 和 Managed Database。
比較務實的用法是:本機用 Compose 跑齊整套環境,正式部署時把每個 service 對應到平台上的獨立服務。
services:
web:
build: .
ports:
- "8080:8080"
environment:
ASPNETCORE_URLS: http://0.0.0.0:8080
ConnectionStrings__Default: ${DATABASE_URL}
depends_on:
- db
db:
image: postgres:16
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
depends_on 只代表啟動順序,不代表資料庫已經 ready。線上平台很多也沒有直接等同 depends_on 的功能——實際後果就是程式先起來、DB 還沒好、程式一開始去連就拿到 Connection refused,日誌裡一堆錯誤。
ASP.NET Core 程式應該自己做連線重試或啟動健康檢查,不要把「我本機 docker compose up 可以跑」當成正式環境保證。
本文中有些服務根本不讓人用 docker compose(或是在進階方案),所以選擇佈署平台,同時也會影響程式開發的架構,不用東西都做完,在本機執行得很開心,然後發現根本無法佈署到線上。
資料庫跟容器放一起,有什麼問題?
方便是方便,但正式環境請拆開。
本機開發時,compose.yaml 裡把 web 跟 db 放在同一個檔案很自然,啟動一行指令就搞定。但到了 PaaS 正式環境,資料庫跟 container 綁在一起有幾個實際問題:
- container 重建就得重建資料庫:Volume 問題上面講了,資料庫資料也一樣,如果 db 資料沒掛好 Volume,每次重新部署資料就沒了。
- 備份要自己搞:自己跑的 DB container,快照、備份、版本升級都要自己處理。各家 PaaS 的 Managed Database 通常內建自動備份跟更簡單的版本管理,把這件事交出去比較省心(備份或snapshot通常需要額外的$$$$)。
- 連線字串不要寫死在程式裡,密碼應該透過環境變數傳進去。
ASP.NET Core 的設定系統會依序讀 appsettings.json → appsettings.{Environment}.json → 環境變數,環境變數優先級最高,正式環境透過平台注入連線字串不會動到程式碼本身:
// appsettings.json 只留空值或本機用的
"ConnectionStrings": {
"Default": ""
}
// Program.cs — 環境變數會自動覆蓋 appsettings
var connStr = builder.Configuration.GetConnectionString("Default");
Docker + 雲端才不是沒訪客就不用付錢
很多人看完雲端服務的廣告文案,以為系統會像計程車一樣,有客人才出車、沒客人就完全不花成本。但真實情況通常複雜得多。
在有些程式與IT架構,容易有時候訪客多一點就當機,所以可能為了淡季或幾天活動,要準備規格高一點的設備全年一直開著,這聽起來就成本很高。
但是在現在的雲端架構,滑鼠點一點就隨時可以加開機器,直接水平擴展,但不要覺得這會比較便宜。
先理解一件事:PaaS 上「水平擴展」的意思通常是同一份程式碼跑多個 container 實例,流量由 Load Balancer 分配進來,這兩句不懂沒關係,重點是那些會自動水平擴展的服務,還有 Load Balancer,都要另外付錢才能動,而且一但被惡意流量攻擊,就會產生天價帳單。所以要再多買一些貴貴的某種防護服務。
然後如果程式預設是使用 Session based 的架構(東西在記憶體,或每個 container 彼此不共享),那水平擴展後使用者就很容易被登出了。
這當然也有很多解決方式,例如把 Session 狀態外部化。用 Redis 或其他服務當 Session Store,哎呀,所有 container 連同一個 Redis,或是用 JWT 之類的驗證架構。
這個其他服務、改程式架構,又要錢了,而且設備規格一樣要開很高,不然在高流量瞬間併發下,又成為系統脆弱的一環。
然後水平擴展架構實際上也不是真的「沒訪客時不用付錢,有訪客才付錢」,在某些情況下需要先預熱預先直接擴展出一堆設備,不然一堆人瞬間擠進來時,系統根本來不及反應。
例如 Kubernetes 的 Auto Scaling 通常需要先把新的 Pod 建立起來、下載映像檔、啟動程式、通過健康檢查之後才能接流量;大型雲端服務甚至會要求預先保留特定區域的運算容量(Capacity Reservation),就算沒使用到這麼大的量,還是要照樣付錢。
所以 Docker、Container、Kubernetes 這些技術解決的是「比較容易擴充」,而不是「0訪客=0成本」。流量高峰時該買的主機、資料庫、Redis、負載平衡器、防護服務,最後還是要買,只是從自己買機器變成改付雲端帳單而已。
Fly.io:CLI 部署,但免費方案已經沒了
公司在 2017 年成立,首頁文案是
Deploy App Servers Close to Your Users.
Run your full stack apps (and databases!) all over the world. No ops required.
Fly.io 的特色是可以直接從本機用 CLI 推送,不一定要先把 code 丟到 GitHub。支援 Docker,在日本、香港、新加坡都有機器。
免費方案現況(2026):Fly.io 在 2024 年底正式取消了永久免費方案。新帳號只有 2 小時或 7 天的試用額度(先到先結算),之後一定要綁信用卡才能繼續。一個最低規格的永遠開著的 app(shared-cpu-1x、256 MB RAM)大約每月 $2 美元,加上 Volume、流量費用通常會到 $5 以上。如果只是要短期測試 ASP.NET Core Docker,Fly.io 仍然很適合;若完全不想綁卡,要先三思。
部署流程
- 在 fly.io 註冊帳號
- 參考 Installing flyctl 安裝命令列工具
- 執行
flyctl auth login登入 - 切到本機專案目錄(沒切到目錄會跑到當掉)
- 參考 Deploy Your Application via Dockerfile 用
flyctl launch進行專案設定,選機器位置


- 初次使用會跳出 Windows 防火牆的通知,按允許,等它執行
- 跑完之後會問要不要順便 deploy,就先讓他跑看看
- 終端機視窗看到 deployed successfully 之類的訊息就表示完成了

一開始 flyctl deploy 都會跑超久,大概 5 分鐘,然後會顯示 Failed due to unhealthy allocations,網頁也打不開。後來參考 Troubleshooting your Deployment,修改 Dockerfile 的 internal_port,改完之後就正常了。後來有幾次還是會碰到 Failed due to unhealthy allocations,但是直接重新 flyctl deploy 又好了。
這裡有個值得說清楚的點:Dockerfile 如果同時 EXPOSE 了好幾個 port,各家 PaaS 不見得知道你的程式實際上在監聽哪一個。
Fly.io 的 fly.toml 要明確指定 internal_port,Render 跟 Railway 也有類似的 port 設定。Dockerfile 裡的 EXPOSE 只是宣告說「我有可能用這幾個 port」,不是告訴平台要把流量導到哪一個——設錯就是 health check 一直失敗、服務一直起不來。
本機程式有再更新的話就用 flyctl deploy 再重新發佈。deploy 之後用 flyctl open 會開啟一個 [專案名稱].fly.dev 的子域名。

到 fly.io 官網的 dashboard,有一些運作情況和圖表可以看,需要機器異常通知的話有提供 API Metrics on Fly。
Docker Compose 的話,官方不支援把 docker-compose.yml 原封不動丟上去,多服務專案要拆成 Fly App、Managed Postgres、Redis 等資源分別管理,可參考 Running Multiple Processes Inside A Fly.io App。
測完之後要把程式暫停,照著文件輸入指令……結果指令已經被停用了,但文件還沒更新……

外掛 volume
先幫專案建立一個儲存集區:
flyctl volumes create 取一個名字 --region sin --size 1
- Region 的代號可參考 Fly.io – Regions
- size 的話單位是 GB,而且只能接受整數,所以打 0.5 是不行的
- 1 GB Volume 目前大約每月 $0.15 美元,就算機器停了 Volume 費用還是繼續計
參考 Fly.io – Volumes 在 fly.toml 設定 volume 資訊:
[mounts]
source="取一個名字"
destination="/wwwroot/"
剛剛有講說測試程式會用到 Puppeteer,程式在本機執行時會在專案資料夾產生一包好幾百 MB 的 local web browser,flyctl 要自己手動排除那個資料夾,不然傳上去的檔案超級大,很浪費佈署時間。
設定 env 參數
要從外部把 SQL ConnectString 塞進去的話,可以參考 Secrets and Fly Apps,使用以下任一個都可以設定成功。如果 value 中間會輸入到分號(;),要加上反引號當 escape string:
flyctl deploy -e name=value
flyctl secrets set name1=value1 name2=value2
測試辨識功能,找一張 YouTube 的影片封面圖片,中英文的辨識效果都還不錯:

另外也提供自訂域名+免費 SSL,可以把 fly.dev 的子域名當成 CNAME,設定對應到自己的域名底下,然後用 flyctl certs create mydomain.com 簽一張 Let's Encrypt 的免費 SSL 憑證。這功能在本文中介紹的其他平台,有幾個是要付費的。
Render.com:部署最順,但免費版睡著客戶會等一分鐘
這也是另一間在這次 Heroku 事件中獲得多次曝光的服務,這家公司在 2019 年成立,個人覺得 render 這名字取得不好,3D 繪圖領域的用語有 render,網頁前端的用語有 render,現在後端也來搞個 render……是一個線上服務?這樣要怎麼保證使用者搜尋 render 就找到這個服務?菜市場名要做 SEO 就有點風險。
他家官網上就有 Render vs Heroku 的詳細比較,服務比 Fly.io 多一點,還有 Redis 可以用:

這次用的幾個平台,Render 算是最快佈署成功的,跑完就可以看到網頁,不會有一些奇怪的錯誤要修。
免費方案現況(2026):Free Web Service 仍然存在,不需要綁信用卡。但免費版 15 分鐘沒有流量就會 spin down,下一次有人進來要等它冷啟動,這個過程大概 30 到 60 秒。對 demo 網站可以接受。
但如果是 OCR API、Webhook、客戶後台,客戶點進去等一分鐘毫無反應,通常第一反應是「網站壞了」。如果要避免 spin down,Starter plan 每月 $7 美元。Free Postgres 資料庫建立後 30 天會被刪除,這點要特別注意。
註冊時不會強制要求綁信用卡,不過如果到下圖這個畫面,不綁信用卡的話,一大半功能都是點不進去的:

不過 Web services 這個是可以不綁信用卡直接免費使用的,RAM 512MB 比 Fly.io 多了整整一倍:

Fly.io 是可以直接從本機推送,Render 是要先關聯 GitHub 或 GitLab。這邊有件怪事,GitHub 授權是可以只授權單一個 repository 的,但是如果只選擇一個 repository,render 會一直跳走,無法下一步,所以只好先開放帳號底下全部的 repository。或是先把 repository 改成公開,然後用 public repository 功能,這樣就不用特別授權了:

環境一樣是選擇 Docker:

Render 的區域比 Fly.io 少很多,這邊選新加坡:

直接在網頁上操作,不用裝什麼命令列工具,一次就 build 成功。系統會生成一個 https://[專案名稱].onrender.com 的子域名,也支援 custom domain。每次綁定的 GitHub 有新的 push 的時候就會觸發 auto deploy,但有時候不會馬上執行,要等一下。

Render 不支援直接跑 Docker Compose,而是用 render.yaml / Blueprint 把多個服務、Disk、環境變數拆開管理。
外掛 volume
如果有讀檔跟寫檔需求,就要直接在專案裡面建立 Disk 功能,但是免費方案不能使用。真的付錢開通 Disk 服務之後,要再開通他們的另一個 Blueprint 服務,然後用 render.yaml 設定 mount disk:

設定 env 參數
可參考 Render – Configuring Environment Variables and Secrets,網頁上直接有 UI 可以設定,設定之後不用自己手動按 Deploy,就是設定之後有點延遲,不會馬上生效(例如把 env 的某個 key 刪掉,程式在幾分鐘內重新整理都還是讀得到值),猜測可能是要等平台在背景自動 Deploy 完成:

Railway.app:用量計費、多地區,$5/月 Hobby plan 起
Railway 是 2020 年成立的,2021 年公開推出這個服務,首頁標語是
Bring your code, we'll handle the rest.
Made for any language, for projects big and small. Railway is the cloud that takes the complexity out of shipping software.
註冊之後也不用綁信用卡,只是需要同意條款,滿 13 歲、不可以拿來放一些非法程式之類的:

支援的功能大致有這些,幾種常見的資料庫、Redis、範例小程式、從 GitHub 導入等:

唉呀,竟然沒有想到有這些玩法!這硬體規格大概只能挖一些小幣吧。
一樣需要授權 GitHub 中建好的 private repository,可以只授權單一專案,到這邊還沒什麼問題。Deploy 完畢,建置成功之後,要自己按產生網址,然後才會給一組 https://[專案名稱-production-abcd.up].railway.app/ 之類的網址:

結果點進去之後碰到錯誤訊息
Application Error Is your app correctly listening on $PORT?
不知道是什麼?直接把訊息 Google 又找到 railway 官方的說明 Exposing Your App,到 Railway 網頁上的專案環境變數 Variables,把自己在 Dockerfile 裡面用到的 port 設定上去就好了:

地區與 Docker Compose(2026 現況):Railway 現在支援美國東西岸、歐洲阿姆斯特丹、新加坡等多個部署區域,跟當初只有美國西岸已經不同。Docker Compose 也有匯入與轉換流程,但重點是「把 Compose 裡的 service 對應成 Railway 專案內的多個 service」,不是線上直接執行同一份 Compose 檔。
費用現況(2026):新使用者有一次性 $5 試用額度,30 天後或額度用完後需要升級。Hobby plan 是每月 $5,包含 $5 的資源使用額度(CPU、RAM、流量);用量超過才另外計費。
小型 side project 通常 $5 以內跑得住,但如果放一個一直開著的 container,一個月跑下來就超過了,要養成看 usage dashboard 的習慣。和 Fly.io 一樣,Railway 現在不適合「找個永遠免費的後端主機」,但 $5/月的 Hobby plan 對有實際需求的小型專案來說算合理。


文件及服務內沒特別看到關於 volume、mount、disk 之類的東西,只有寫要自訂 Dockerfile 時要用 RAILWAY_DOCKERFILE_PATH 這個環境變數。
Railway 還有推薦者計畫,從這個連結 https://railway.app?referralCode=gKKRLU 註冊,我會得到 $5 的使用額度(附上備註,有人用的話我拿 $5 額度,不一定要點)。
四、GCP Cloud Run:台灣有節點,但要特別注意相關服務的花費
Cloud Run 是 GCP 在 Serverless 類別裡面的一個服務,跟 Cloud Functions 和 App Engine 並列,官網的說明是:
Build and deploy scalable containerized apps using your favorite language on a fully managed serverless platform.
第一步就是先啟用 Cloud Run 服務,然後選擇程式是從哪裡來的,可以選擇從容器影像檔或是從原始碼存放區。
不知道要怎麼讓它直接吃 Docker Hub 的檔案,有嚴格的規定,或是要放在 GCP 的另外兩個服務 CONTAINER REGISTRY 或 ARTIFACT REGISTRY 裡面。
Docker image 來源網址應採下列格式:[region.]gcr.io/repo-path[:tag 和/或 @digest] 或 [region.]pkg.dev/repo-path[:tag 和/或 @digest],
剛剛就已經用過 GitHub 了,所以這邊選擇 GitHub,GCP 也支援 Bitbucket 等來源:

一樣需要開通另一個 Cloud Build 服務,然後授權 GitHub 專案,一樣可以只授權單個專案:

Cloud Run 可以選的規格比較高,也有台灣區 Asia-east1 可以選:

之後就是等它跑完佈署,一樣會給一個免費網址 https://[專案名稱+一些序號].run.app:

中途想要換建置來源?可以點上面的「編輯及部署新的修訂版本」跟「編輯持續部署功能」,讓同一個網址 *.run.app 輕鬆抽換成其他內容。
設定 volume
官方有提供兩種設定方式,看起來都不太簡單:
- 将 Cloud Storage FUSE 与 Cloud Run 搭配使用
- 将 Filestore 与 Cloud Run 搭配使用——開頭直接寫「注意:使用 Filestore 的容器实例的最低每月费用很高」
設定 env
可以直接在「編輯及部署新的修訂版本」內輸入環境變數,會明碼顯示:

資料庫連線字串比較隱密,這邊使用在同一個區域下面的參照密鑰功能,啟用另一個服務 Secret Manager(低用量有免費額度)。也可以參考 Cloud Run – Use environment variables 用 yaml 或其他設定方式。
奇怪問題
- 網頁上中文版各處翻譯不一,同一個專有名詞在頁面各處有 N 種翻譯,甚至 Docker image URL 還翻成圖片網址。
- Cloud Run 佈署成功,但網頁等很久都打不開?結果再重新佈署一次又會好。
- GitHub 專案推送更新後,Cloud Build 有時候不知道為啥沒動靜?要再手動按按鈕,或是改檔案再 git push 一次又會成功觸發。
- Cloud Run 版本佈署成功後,網頁還是舊的,又要回到「編輯及部署新的修訂版本」重新選一次最新佈署的映像檔,再佈署一次才是新網頁。
GCP Cloud Run 收費嗎?
因為我的 GCP 帳號已經有綁過信用卡,所以這次這樣用要錢嗎?這問題其實很複雜。
每次版控系統推送帶動 Cloud Build 建置 Docker image,Cloud Build 是每天前 2 小時建構時間免費,超過的每分鐘 $0.003 美元,本次測試的 .NET Core 程式每次大概跑個 1 分鐘出頭,一天不要 push 太多次就沒事。
Cloud Build 完的 Docker image 會被放到 Container Registry,只會針對 Docker 映像檔耗用的 Cloud Storage 容量和網路輸出流量收取費用。除非不小心啟用了安全漏洞掃描(Container Registry Vulnerability Scanning),才會有費用(掃一個 docker image 要 0.26 美金):

(只是一個基本範例專案,從 nuget 裝幾個套件,掃一下就跟打開潘朵拉的寶盒一樣)
每一次 build 都會自動把每個版本的 Docker image 儲存到 Cloud Storage,Cloud Storage 有免費額度,但本例測試程式的 docker image 就已經接近 100MB,要是沒去清的話很快就超出免費額度了。
Cloud Run 本身也有免費額度,可以用 Google Cloud Pricing Calculator 算看看,如果是硬體規格非常低、非公開的小功能,應該不會用超過。
後來帳單來了之後,Cloud Storage 的部分確實產生一些費用,先把舊的檔案清掉再看看。以這次的測試規模,大概每月 $0~$2 美元,但舊的 image 要記得定期清,不然費用會慢慢往上爬。
同場加映:AWS 與 Azure 的類似服務
AWS 那邊類似的、不用自己灌作業系統的服務,應該是 AWS Fargate 或 AWS Elastic Beanstalk 或 Amazon Lightsail 裡面的容器服務(最低階的 Nano 方案每月 $7 USD,per node 512 MB RAM,0.25 vCPUs)。
值得一提的是如果之前沒用過 Amazon Lightsail 的 VPS instances,某些方案有初次使用前三個月免費的額度,VPS 自己灌 Docker 之後應該也可以讓網頁程式跑起來,短期使用可以參考看看:

Azure App Service 提供一個最低階的 F1 免費方案,每天有 60 分鐘的 CPU Time 使用額度。Azure 自己的平台跑 ASP.NET Core 當然是沒問題的,也支援 Docker,但我怎麼試 Docker 容器都失敗,佈署時會碰到「參數 LinuxFxVersion 具有無效的值」。後來是改用程式碼佈署,選擇 .NET + Linux,然後用 Github 推送程式碼上去:

因為這邊不是用 Docker 容器,所以 Dockerfile 做過的時區設定沒效,時間一樣會跑掉,要改在組態 > 應用程式設定加上 TZ=Asia/Taipei(Linux 環境的加法,Windows 環境的又不一樣了)。
可惜 PuppeteerSharp 的瀏覽器無法啟動,出現 Failed to launch browser! 的訊息。
建置完一樣會給一個 https://[專案名稱].azurewebsites.net/ 免費網址,但是 F1 免費版方案,一堆功能都是鎖住的:

紫紅框下面兩大塊就是付費才有的功能,一個月 2000 多元起,所以 mount disk 的功能也就沒去試。
這個服務會有 Cold Start 限制,20 分鐘沒用到就會把資源釋放掉,「組態」>「一般設定」裡面有個 Always On 的選項,不過免費方案是鎖住的,要到更高的方案才能用:

如果只是拿來跑一些小程式的話可以用看看,一樣觀察帳單會不會多出什麼奇怪的流量傳輸費用。
五、Mogenius(已停止免費方案,僅供參考)
這個是一家德國公司,免費方案在 2023 年三月就關了,現在不建議列入選項——這段留著當歷史紀錄。

這次用的幾個,Render 跟 Mogenius 算是最快佈署成功的,跑完就可以看到網頁,不會有一些奇怪的錯誤要修。
Mogenius 在 Service 裡面就有原生支援 ASP.NET Core,不過建置過程有顯示建立 k8s 的訊息,最後應該還是跑在 Docker container 裡面。
Hostname 裡面會配一個 https://[github專案名稱-環境-Mogenius專案名稱-佈署代號].mo1.mogenius.io 的網址,機器在德國,不過有掛 Cloudflare 專業版,都會從台北節點來,靜態檔案的速度不會太差。
要使用 custom domains 則需要付費升級。官方說明 Mogenius – Deploy your service with Docker 有寫不支援 Docker compose。
設定 volume:要設定 container 重建之後檔案不要遺失,可參考 Mogenius – Working with persistent storage,在網頁介面的 ENV VARS 直接把參數加上去,不用加在自己的 Dockerfile 或改程式。這家比較特別的是網頁介面直接提供一個 File Browser,讓人可以直接看掛載磁碟裡面的檔案。
這類平台的免費方案調整速度很快,當初測起來最順的服務,不一定幾年後還適合推薦給新專案。
六、Zeabur:台灣開發者現在最常拿來試的選項
Zeabur 是現在可以優先試的 Heroku 替代方案之一,尤其適合小型 Web API、Side project、Demo 服務,或是想把前後端、資料庫、Redis、物件儲存放在同一個專案裡的人。
Zeabur 的特色不是「永遠免費」,而是操作流程比較接近新一代 PaaS:連 GitHub、偵測框架、每次 push 觸發部署、給一組公開網址、環境變數在後台設定。官方文件也列出 .NET 支援。
費用現況
之前早期推廣期有很多優惠,例如:
- 推廣別人使用,可以拿到一些使用額度。所以會看到很多科技部落客會教大家去 Zeabur 跑自己的什麼小程式或 AI 工具。
- 有每月 $5 美元的 Dev Plan,使用某些共享叢集服務可以不用再付錢(就付超過的部分)
但後來 2026/2 起新專案不再開放共享叢集,所以新開的專案就只能從他們的後台,用比較優惠的金額去訂雲端主機,或是自己買好之後,安裝他們的程式,統一在他們的管理介面操作。
然後 2026/6 月起,那些透過 Zeabur 買的雲端主機漲價了,每個月多一兩美金到幾十美金(高階機型)的都有,新舊客戶都漲。不過同時期也有國外原廠漲價,這就是大環境問題。
「跟 Zeabur 買vps,比跟原廠買還便宜」本來這是一個賣點,後來也讓一些使用者覺得這都是一場夢,現在夢該醒了。
Zeabur 適合誰
適合想要「比自己買 VPS 少管很多事情,但又不想直接跳進 AWS/GCP/Azure 控制台」的人。對台灣開發者來說,學習成本比一些純英文雲端平台低,也比較容易找到中文討論。
而且 Zeabur 後來還開始賣 AI Hub(Claude/Gemini/OpenAI等API)、Email 寄件服務、網域,某些需求下也算是把要用的東西在同一家一次買齊。不像本文中有些服務就是真的只做程式上線佈署這塊,網站要網站域名/網站內有用到AI/網站要寄信? 只能自己另外買。
初期還可以到他們的 Discord 直接開單跟真人討論,這在三大公有雲根本是天方夜譚,沒額外買支援方案,多半就只有產品論壇或機器人客服而已。
他們文件有說 Zeabur 目前還不支援從 Docker Compose YAML 進行部署。,需要轉換成另一種 Zeabur Template YAML 格式。
我會把 Zeabur 定位成「推薦試用與小型上線」,不要把它當成有免費服務可以狂用的廠商。它比自己架 VPS 省事,比三大雲簡單,但只要服務是正式收錢、會影響客戶營運,就應該把備份、預算、流量、停機通知、供應商風險、系統莫名其妙斷線等危機,一起考慮進方案。
因為我後來沒有用他們的服務,所以推薦碼我也不放了。
其他選項,懶人包
上面介紹了好幾個真的可以把小型的 ASP.NET Core 程式跑起來的,國外還有很多類似可以跑後端程式和資料庫的服務,就不再一一截圖使用心得:
- Northflank 要到 Deploy 時才會要求輸入信用卡
- Porter 一開始看到免費方案 Up to 10 vCPU, 20 GB memory 覺得很猛,一用之後發現很妙,是幫忙把我的 GitHub 上的專案程式碼編譯之後,發佈到我的 GCP 或 AWS 帳號裡面去,所以大部分網站成本還是自己出錢。
- Koyeb
- Qoddi 免費版號稱無限流量,也不會休眠
- Deta.sh 亞洲區可以選新加坡跟印度,號稱永久免費,跟 fly.io 類似,安裝 CLI 工具然後從本機推送。
找替代 Heroku 的平台時,不要只搜尋「free Heroku alternative」,要直接查最新 pricing、sleep policy、Dockerfile support、Compose migration、custom domain、volume、backup、outbound bandwidth 與服務終止政策。這份清單裡有些服務的狀況幾年後可能又不一樣了。
跑靜態網頁的,以後有機會再出一篇。
幾個平台跑完,選哪個?
明明看似是一樣的程式,放在不同系統上,就會有不同的操作邏輯跟錯誤訊息需要處理,例如有些平台有自己的 toml/yaml 格式。如果實際專案情況更複雜,有些可能就不太合用。
這種把程式碼放在 Github 當 Source repository,然後在雲端 build & deploy 的流程,最怕的就是 Github 一個月會故障好幾次(Github Incident History),造成工程師可以工作、主機也正常,但卡在中間的流程斷掉,而無法更新網站,為了保險又得要設計其他麻煩的備案。
各服務佈署完程式之後,都會給一個有 HTTPS 但名字通常很複雜的子域名網址,但因為詐騙網站也可能使用這些域名,所以這種網址可能會在社群網站貼文時被封鎖:

使用好的軟體或服務,付費支持讓它支撐下去是很重要的。自己做軟體跟設計的人,一方面覺得客人都跑去用免費的,都不付錢買我的服務;然後又覺得我東西就是要蹭免費的,這心態不是很矛盾嗎?
免費額度可以拿來測試,不應該拿來當商業專案的基礎承諾。若要正式營運,請把每月 $5~無上限美元的基礎平台成本當成正常成本,不要再期待所有後端服務都能永遠免費。
找替代 Heroku 的平台時,不要只搜尋「free Heroku alternative」,要注意 sleep(cold start)、Dockerfile 和 Docker Compose 支援性、custom domain、volume、backup、outbound bandwidth 與服務終止政策。
跑靜態網頁的,以後有機會再出一篇。