侧边栏壁纸
  • 累计撰写 42 篇文章
  • 累计创建 32 个标签
  • 累计收到 2 条评论

目 录CONTENT

文章目录

不用绑卡!Daytona 免费开 4 核 8G,还能跑 Windows,100 美元永不过期

Administrator
2026-11-02 / 0 评论 / 0 点赞 / 190 阅读 / 0 字

核验时间:2026-11-02,基于实际走通的流程写成。

价格和规则以 Daytona 官网当时页面为准,本文不承诺永久免费。

一句话先说清楚:Daytona 不是传统虚拟主机,也不是 cPanel 建站面板。

它是给 AI Agent 跑代码的隔离沙箱,适合开发、演示、跑 Python 服务,不适合直接当长期正式网站用。正式上线,建议把代码导出到 Cloudflare Pages、Vercel、Netlify 这类托管。

目录

  • Daytona 是什么
  • 费用先讲清楚,别被 200 美元误导
  • 注册前先准备一个好 IP
  • 注册步骤
  • 创建沙箱:选 daytona-small 就够了
  • 跑第一个静态站
  • 拿到公网地址:不要自己拼域名
  • 进阶:跑一个像样的 Flask 服务
  • 生命周期:停止、归档、删除是不一样的
  • 省钱与安全清单
  • 常见问题
  • 正式上线建议
  • 参考链接

Daytona 是什么

Daytona 现在叫自己 Agent Cloud。

它的核心是给 AI Agent 跑代码的隔离沙箱。一个沙箱就是一台隔离的 Linux 容器或虚拟机,有自己的文件系统、网络、CPU 和内存,号称 90 毫秒内就能启动,还支持快照、暂停、恢复、SDK、CLI 和 API。

它能做什么

  • 在云端跑 Python、Node.js 代码和 Web 服务,并通过预览链接给别人看
  • 给 AI Agent 一个隔离的工作区,跑测试、跑脚本、做演示
  • 用快照保存一套装好依赖的环境,反复开新沙箱

它不能当成传统主机来用

  • 没有一键 WordPress,没有 cPanel,没有域名绑定面板
  • 预览地址是临时代理域名,不是你自己的域名
  • 沙箱停了,网站就打不开了;删了,数据就没了

费用先讲清楚,别被 200 美元误导

官网定价页写的是 200 美元免费算力,但实际到账是分两笔,笔者钱包截图验证如下:

项目金额条件
第一笔免费额度100 美元邮箱验证后到账,永不过期
第二笔免费额度100 美元绑卡后到账,合计 200 美元
付费额度0 美元未绑卡、未充值时为 0

第一笔在钱包里显示为 Email verified credits,展开后写着 Never expires。

适用范围包括 Container、Linux、Windows、Android 沙箱。

计费方式

计费是按秒计费,按预留资源算,不是按访问量算:

资源价格
vCPU0.0504 美元/小时
内存0.0162 美元/GiB/小时
存储0.000108 美元/GiB/小时,首 5 GiB 免费
Windows 沙箱另加 0.0858 美元/vCPU/小时
GPU 沙箱例如 RTX 4090 约 0.57 美元/小时,免费额度不可用于 GPU 沙箱

能跑多久

以最便宜的 daytona-small 为例:

  • 配置:1 核 + 1 GiB 内存
  • 每小时约 0.0666 美元
  • 每天约 1.6 美元
  • 100 美元大约能连续跑 62 天

间断用、不用就手动停止,能撑得更久。

扣款顺序是免费额度先于付费额度。同一个计费月内,后补的免费额度可以回溯抵扣已经用付费额度结算的用量,月结后锁定。

账单还有最多 48 小时的延迟,余额不会实时立刻变化。

第二笔 100 美元的有效期,在笔者截图时没有显示,不能默认它也是永不过期。到账后请自己点开钱包里的 See breakdown and expiration 再确认一次。

注册前先准备一个好 IP

这一点很多教程不写,但注册失败常常就卡在这里。

所谓“好 IP”,不是买来的代理,而是指你自己干净的个人网络。

通用注册风控的规律是:

  • 真实用户通常来自家庭宽带、手机流量和公司网络
  • 批量造号、薅免费额度、绕过封禁的行为,通常来自机房网络、免费 VPN、数据中心代理、公开代理和 Tor,这些类型最容易在注册时被直接拦截

实操建议

  1. 优先用家庭宽带或手机流量注册,不要一上来就用机房、免费 VPN、公共代理、Tor 或 iCloud Private Relay 这类出口。
  2. 不要用多人共用的免费节点反复注册。一个节点被很多人用来注册过,信誉早就被拉低了,换节点比反复点注册更有效。
  3. 如果你本来在用 VPN,先试试关掉 VPN,用本地网络注册;如果必须用 VPN,就固定一个口碑较好、共用人少的节点,不要频繁换国家、换节点。
  4. 失败后不要马上连续重试。短时间内多次失败,风控分数可能越刷越低。换网络、换一个干净的浏览器无痕窗口,隔一段时间再试一次。
  5. 不要用同一个 IP 和同一台设备批量注册多个账号,这很容易被判定为滥用。
  6. 这条是实操经验,不是 Daytona 官方公开写的规则。具体以 Daytona 当时的报错为准,如果多次失败,联系官方支持比反复试更稳。

注册步骤

  1. 打开 Daytona 官网:https://www.daytona.io
  2. 注册账号并完成邮箱验证。
  3. 进入左侧 Wallet,确认 Free credit balance 是 100 美元。
  4. 展开 See breakdown and expiration,确认是 Email verified credits、Never expires。
  5. 先不要急着绑卡。只用第一笔 100 美元,已经足够跑通本教程的全部演示。
  6. 如果你决定拿第二笔 100 美元,再去 Payment methods 里点 Add payment method。

绑卡本身不会马上扣费,但免费额度用完后,超出的按量费用会走这张卡,额度快用完前一定要先停沙箱。

注册时不要在任何公开画面里露出你的 API Key、密码和银行卡信息,拍视频更要先打码。

创建沙箱:选 daytona-small 就够了

  1. 左侧点 Sandboxes,再点 Create Sandbox。
  2. Name 可以填一个自己记得住的名字,例如 my-sandbox,不填就默认用沙箱 ID 当名字。
  3. Source 有两个选项,区别如下:
选项意思适合谁
SnapshotDaytona 提前建好的环境模板,已经装好系统、Python、Node 等常用工具,选了就能马上启动新手、做演示,直接选这个
Image你自己指定的公开 Docker 镜像,例如 ubuntu:22.04,Daytona 会先把它建成快照再开沙箱,第一次会慢一点需要完全自定义环境的人

镜像必须是公开可访问的,还要带具体的 tag 或 digest,latest、lts、stable 这类标签是不支持的。如果两个都填了,快照优先。

  1. 在 Snapshot 列表里选 daytona-small。官方表就是 1 核、1 GiB 内存、3 GiB 磁盘,容器类型,这已经是系统快照里最小的配置,也是 CPU 和内存的最低档。
  2. 下面那个 Ephemeral 千万别勾。勾了就是“停了就自动删沙箱”,网站数据就没了。
  3. 点创建,等状态变成 Started 再往下做。

其他快照不是更小

  • daytona-medium:2 核 4 GiB
  • daytona-large:4 核 8 GiB
  • daytona-vm-small:也是 1 核 1 GiB,但它是 Linux 虚拟机类型
  • daytona-gpu:带 GPU,且免费额度不能用
  • windows-medium:Windows 的,更大更贵

创建后要确认的几项

  • 状态:Started
  • Preview access:Public,这样预览链接不用 token 就能打开
  • Auto-stop:如果你创建时是 Disabled,闲置也不会自动停,会一直按 Started 计费
  • Auto-archive:例如 7d,意思是手动停止满 7 天后自动归档
  • Auto-delete:建议保持 Disabled

跑第一个静态站

点顶部 Terminal,在沙箱里粘贴下面这段:

mkdir -p ~/site && cd ~/site
cat > index.html <<'EOF'
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>我的网站</title>
</head>
<body>
<h1>Hello from Daytona</h1>
<p>我的网站跑起来了</p>
</body>
</html>
EOF
nohup python3 -m http.server 8000 --bind 0.0.0.0 > /tmp/site.log 2>&1 &
sleep 2
curl -I http://127.0.0.1:8000

注意两点

  • index.html 里一定要有 <meta charset="utf-8">,否则中文在浏览器里很容易变乱码。
  • curl 第一次如果报连不上端口,很可能只是服务还没起来,等 2 秒再测一次,不要马上重复跑 nohup。重复跑会报 Address already in use,因为 8000 端口已经被第一个进程占了。

curl 返回 HTTP/1.0 200 OK,就说明沙箱里的服务已经起来了。

拿到公网地址:不要自己拼域名

预览地址的通用格式是:

https://{端口}-{沙箱ID}.{代理域名}

例如,端口是 8000,沙箱 ID 是 e1fd010f-05a6-4b59-b880-1f32be3bda42,笔者实测打开的地址就是:

https://8000-e1fd010f-05a6-4b59-b880-1f32be3bda42.proxy.daytona.works

但代理域名那部分不要自己猜。官方文档里的例子就不统一,出现过 proxy.daytona.work、proxy.daytona.works 和 daytonaproxy01.net。

最稳的办法,是在你自己电脑的终端里装好 Daytona CLI 并登录后跑:

daytona preview-url <沙箱ID或名字> --port 8000

它打印出来的那个地址就是准的。

因为你的沙箱是 Public,网站端口不用 token 就能直接打开。第一次在浏览器打开可能会先出现风险提示页,点继续就行。

注意,网页终端本身即使是 Public,也还是要登录凭证才能进,这和网站预览是两回事。

签名预览链接是另一种临时分享方式,默认只有 60 秒,最长 24 小时,不适合当长期公开地址用。

进阶:跑一个像样的 Flask 服务

静态页只能证明通了,拍教程最好再跑一个真后端。

下面这个演示站一个文件就能跑,有首页、密码生成器、待办清单、留言板和 JSON 接口,改完刷新就能看效果。

第一步:停掉旧服务,装 Flask

pkill -f "http.server 8000" || true
mkdir -p ~/pyservice && cd ~/pyservice
test -d ~/venv || python3 -m venv ~/venv
source ~/venv/bin/activate
pip install flask

第二步:生成完整的 app.py

把下面这份 app.py 整段粘贴生成,结尾的 PYEOF 是结束标志,不要拆开:

cat > app.py <<'PYEOF'
import random
import sqlite3
import string
import sys
import time
from datetime import datetime
from flask import Flask, jsonify, redirect, render_template_string, request, url_for

app = Flask(__name__)
DB = "data.db"
START = time.time()

def get_db():
    conn = sqlite3.connect(DB)
    conn.row_factory = sqlite3.Row
    return conn

def init_db():
    conn = get_db()
    conn.execute("CREATE TABLE IF NOT EXISTS todos (id INTEGER PRIMARY KEY AUTOINCREMENT, text TEXT NOT NULL, done INTEGER DEFAULT 0, created TEXT)")
    conn.execute("CREATE TABLE IF NOT EXISTS messages (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, text TEXT, created TEXT)")
    conn.commit()
    conn.close()

init_db()

HTML = """
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>我的 Python 服务</title>
<style>
body { font-family: system-ui, "PingFang SC", "Microsoft YaHei", sans-serif; background: linear-gradient(135deg, #667eea, #764ba2); margin: 0; padding: 24px; }
.container { max-width: 900px; margin: 0 auto; }
.card { background: #fff; border-radius: 16px; padding: 20px; margin-bottom: 16px; }
h1 { color: #fff; }
input { padding: 10px; border: 1px solid #ddd; border-radius: 8px; width: 60%; }
button { padding: 10px 16px; border: 0; border-radius: 8px; background: #667eea; color: #fff; cursor: pointer; }
button.danger { background: #e74c3c; }
.row { display: flex; gap: 8px; align-items: center; padding: 8px 0; border-bottom: 1px solid #eee; }
.row span { flex: 1; }
.done { text-decoration: line-through; color: #999; }
.pwd { font-size: 20px; font-weight: bold; word-break: break-all; }
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 700px) { .grid { grid-template-columns: 1fr; } }
</style>
</head>
<body>
<div class="container">
<h1>我的 Python 服务</h1>
<p style="color:#fff;">跑在 Daytona 沙箱里,Flask + SQLite,真后端,不是静态页。</p>
<div class="card">
<h2>服务器信息</h2>
<p>当前时间:{{ now }}</p>
<p>Python 版本:{{ pyver }}</p>
<p>已运行:{{ uptime_min }} 分钟</p>
<p>接口测试:<a href="/api/time" target="_blank">/api/time</a> <a href="/api/password" target="_blank">/api/password</a></p>
</div>
<div class="grid">
<div class="card">
<h2>密码生成器</h2>
<p id="pwd" class="pwd">点下面按钮生成一个随机密码</p>
<button onclick="genPassword()">生成密码</button>
</div>
<div class="card">
<h2>待办清单</h2>
<form method="post" action="/todo/add">
<input name="text" placeholder="输入一件待办事项" required>
<button>添加</button>
</form>
{% for t in todos %}
<div class="row">
<span class="{{ 'done' if t['done'] else '' }}">{{ t['text'] }}</span>
<form method="post" action="/todo/toggle/{{ t['id'] }}"><button>完成 / 恢复</button></form>
<form method="post" action="/todo/delete/{{ t['id'] }}"><button class="danger">删除</button></form>
</div>
{% else %}
<p>还没有待办,先加一条试试。</p>
{% endfor %}
</div>
</div>
<div class="card">
<h2>留言板</h2>
<form method="post" action="/message/add">
<input name="name" placeholder="你的名字" style="width:20%;">
<input name="text" placeholder="说点什么" required>
<button>留言</button>
</form>
{% for m in messages %}
<p><b>{{ m['name'] }}</b>:{{ m['text'] }} <small style="color:#999;">{{ m['created'] }}</small></p>
{% else %}
<p>还没有留言,第一条就是你的。</p>
{% endfor %}
</div>
</div>
<script>
async function genPassword() {
  const r = await fetch('/api/password');
  const d = await r.json();
  document.getElementById('pwd').textContent = d.password;
}
</script>
</body>
</html>
"""

@app.route("/")
def index():
    conn = get_db()
    todos = conn.execute("SELECT * FROM todos ORDER BY id DESC").fetchall()
    messages = conn.execute("SELECT * FROM messages ORDER BY id DESC LIMIT 20").fetchall()
    conn.close()
    return render_template_string(HTML, todos=todos, messages=messages, now=datetime.now().strftime("%Y-%m-%d %H:%M:%S"), pyver=sys.version.split()[0], uptime_min=int((time.time() - START) // 60))

@app.route("/api/password")
def api_password():
    length = request.args.get("length", 16, type=int)
    length = max(8, min(32, length))
    chars = string.ascii_letters + string.digits + "!@#$%^&*"
    return jsonify({"password": "".join(random.choice(chars) for _ in range(length))})

@app.route("/api/time")
def api_time():
    return jsonify({"now": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "uptime_seconds": int(time.time() - START), "python": sys.version.split()[0]})

@app.route("/todo/add", methods=["POST"])
def todo_add():
    text = request.form.get("text", "").strip()
    if text:
        conn = get_db()
        conn.execute("INSERT INTO todos (text, created) VALUES (?, ?)", (text, datetime.now().strftime("%Y-%m-%d %H:%M")))
        conn.commit()
        conn.close()
    return redirect(url_for("index"))

@app.route("/todo/toggle/<int:tid>", methods=["POST"])
def todo_toggle(tid):
    conn = get_db()
    conn.execute("UPDATE todos SET done = 1 - done WHERE id = ?", (tid,))
    conn.commit()
    conn.close()
    return redirect(url_for("index"))

@app.route("/todo/delete/<int:tid>", methods=["POST"])
def todo_delete(tid):
    conn = get_db()
    conn.execute("DELETE FROM todos WHERE id = ?", (tid,))
    conn.commit()
    conn.close()
    return redirect(url_for("index"))

@app.route("/message/add", methods=["POST"])
def message_add():
    name = request.form.get("name", "").strip() or "游客"
    text = request.form.get("text", "").strip()
    if text:
        conn = get_db()
        conn.execute("INSERT INTO messages (name, text, created) VALUES (?, ?, ?)", (name, text, datetime.now().strftime("%Y-%m-%d %H:%M")))
        conn.commit()
        conn.close()
    return redirect(url_for("index"))

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000, debug=False)
PYEOF

第三步:启动并验证

nohup python app.py > /tmp/app.log 2>&1 &
sleep 2
curl http://127.0.0.1:8000

curl 能看到“我的 Python 服务”就说明起来了。端口还是 8000,所以公网预览地址不用换,打开后按 Ctrl+Shift+R 强制刷新一次就能看到新页面。

关于 /api/password,先讲清楚

它不是你服务器的密码,也不是 Daytona 的账号密码。

它只是现场随机生成一串新密码给你看,每次刷新都不一样,不读、不存、不改任何真实凭证。这个演示站本身也没有登录密码,谁拿到预览地址谁就能打开,所以不要在上面写真实密码和隐私信息。

生命周期:停止、归档、删除是不一样的

状态意思计费数据还在吗
Started正在运行CPU、内存、磁盘全算在,服务可访问
Stopped手动停止只算磁盘文件在,内存清空,进程要重起
Archived归档不计费文件在,移到低成本对象存储,启动会慢一点
Deleted删除不计费不在,只有之前单独做的快照还可能留着

归档不等于删除。归档的前提是先停下来,例如你设置停满 7 天自动归档,就是手动 Stop 之后放 7 天,才会变成 Archived。

归档后点 Start 可以恢复文件,但运行中的进程不会自动恢复,要重新跑启动命令。

真正删数据的是 Delete,而且你截图里 Auto-delete 是 Disabled,不用担心它自己删掉。不过归档毕竟不是备份,重要的网站还是建议在 Filesystem 里下载一份,或者推到 Git 上存一份。

省钱与安全清单

  • 不用就手动点 Stop。计费按预留资源算,没人访问也一样烧钱。
  • 不要用 GPU 沙箱来跑普通网站,免费额度不能用,还贵。
  • 不要把 API Key、SSH 私钥、银行卡、真实账号密码放进终端截图、视频画面和留言板,拍之前用实心黑块盖死,导出前全屏检查一遍,包括缩略图。
  • 密码生成器演示时,口播说一句:这是演示生成的随机串,不对应任何真实账号,演示完就作废。不要拿生成的密码真的去注册并登录一个真实账号。
  • 标题和简介别用“泄露、盗号、破解、免费密码大全”这类词,用中性词,例如“随机密码生成器、Flask 小工具”。
  • 额度快用完前,先备份文件,再决定是停掉,还是绑卡拿第二笔 100 美元。

常见问题

中文显示乱码怎么办?

页面里加上 <meta charset="utf-8">,再强制刷新一次。文件本身是 UTF-8,但浏览器没拿到编码声明时很容易猜错。

报 Address already in use 怎么办?

说明 8000 端口已经被旧进程占了。先 pkill -f "http.server 8000",等一下再只启动一次,不要连跑好几遍。

服务明明在跑,为什么公网打不开?

先看沙箱是不是 Started,再看服务是不是监听了 0.0.0.0 而不是只监听 127.0.0.1,最后确认预览地址是不是 CLI 打印出来的那个,不要自己拼域名。

不手动停,能一直跑多久?

只算第一笔 100 美元、只跑 daytona-small 的话,大约连续 62 天。不会像有些免费主机那样闲置休眠,因为 Auto-stop 是 Disabled,而且容器沙箱本身没有暂停功能。但这不是保证,平台维护、故障仍可能中断,额度用完后也不会无限续跑。

正式上线建议

Daytona 的预览地址适合演示,不适合当正式站域名用。

开发测试完,建议把代码推到 Git,再部署到 Cloudflare Pages、Vercel 或 Netlify;需要后端的话,再另外找 Render、VPS 这类正式托管。

参考链接

0

评论区