Rick Brewster 在博客里写了一句话,语气平静但分量不轻——"终于,paint.net 是我们的了。"从 2004 年 Paint.NET 项目诞生起,这个域名就不在他手里。官网只能用 getpaint.net,一个带着"get"前缀的妥协方案。22 年后,妥协结束了。
一个前缀带来的混乱
getpaint.net 这个域名,从工程角度看没什么问题——站点能访问,SSL 正常,CDN 也能跑。但从用户角度看,它是个持续的摩擦源:
- 用户在浏览器地址栏直觉输入
paint.net,跳到了一个和自己无关的页面。 - 搜索引擎结果里,
getpaint.net和paint.net同时出现,新手不确定哪个是官网。 - 社区讨论、文档引用、第三方教程里,两个域名混用,链接一致性难以维护。
Brewster 没详细公开 22 年间的谈判细节,但域名抢注领域的常态是:持有者没有实际使用意图,却长期占据,等待项目方出价回购。这类"非使用性持有"在 .net 顶级域下尤其常见,因为 .net 历史上对注册审核比 .org 更宽松。
域名迁移的实操:从 getpaint.net 到 paint.net
拿下新域名只是第一步。把一个运行了 20 年的站点平滑迁移到新域名,不丢流量、不断服务,才是真正的工作。以下是典型的迁移步骤,Paint.NET 的场景同样适用。
1. DNS 层:新域名指向现有基础设施
先在 DNS 提供商处为 paint.net 配置记录,指向和 getpaint.net 相同的服务器:
; paint.net — 新域名,指向现有服务器
paint.net. A 203.0.113.42
www.paint.net. CNAME paint.net.
; getpaint.net — 旧域名,保持不变,后续做 301 重定向
getpaint.net. A 203.0.113.42
www.getpaint.net. CNAME getpaint.net.
IP 地址
203.0.113.42是示例,替换为你实际的服务器地址。
2. Web 服务器层:旧域名 301 重定向到新域名
在 Nginx 中,保留旧域名的监听,但所有请求一律 301 永久重定向到新域名对应路径:
# /etc/nginx/sites-enabled/getpaint-net-redirect.conf
server {
listen 443 ssl;
server_name getpaint.net www.getpaint.net;
ssl_certificate /etc/ssl/certs/getpaint-net.pem;
ssl_certificate_key /etc/ssl/private/getpaint-net.key;
# 所有路径一律 301 到新域名
return 301 https://paint.net$request_uri;
}
server {
listen 443 ssl;
server_name paint.net www.paint.net;
ssl_certificate /etc/ssl/certs/paint-net.pem;
ssl_certificate_key /etc/ssl/private/paint-net.key;
root /var/www/paintnet;
index index.html;
# 正常站点配置
location / {
try_files $uri $uri/ =404;
}
}
关键点:用 301 而不是 302。301 是永久重定向,搜索引擎会把权重转移到新域名;302 是临时重定向,权重不会转移,旧域名永远"占着"索引位置。
3. 用脚本批量检查重定向是否生效
迁移上线后,跑一遍检查,确保旧域名的每个重要路径都正确跳转:
#!/usr/bin/env bash
# check-redirects.sh — 验证旧域名 301 重定向到新域名
OLD_BASE="https://getpaint.net"
NEW_BASE="https://paint.net"
# 需要检查的关键路径
PATHS=(
"/"
"/download"
"/forum"
"/doc"
"/releases"
)
for path in "${PATHS[@]}"; do
url="${OLD_BASE}${path}"
expected="${NEW_BASE}${path}"
# -sS: 静默 + 显示错误; -o /dev/null: 丢弃响应体; -w: 只输出状态码和重定向目标
result=$(curl -sS -o /dev/null -w "%{http_code} %{redirect_url}" "$url")
code=$(echo "$result" | awk '{print $1}')
redirect_to=$(echo "$result" | awk '{print $2}')
if [[ "$code" == "301" && "$redirect_to" == "$expected" ]]; then
echo "✅ $url → $redirect_to"
else
echo "❌ $url → code=$code redirect=$redirect_to (expected 301 → $expected)"
fi
done
运行方式:
chmod +x check-redirects.sh
./check-redirects.sh
输出类似:
✅ https://getpaint.net/ → https://paint.net/
✅ https://getpaint.net/download → https://paint.net/download
❌ https://getpaint.net/forum → code=302 redirect=https://paint.net/forum (expected 301 → https://paint.net/forum)
第二条 ❌ 说明 /forum 用了 302 而不是 301,需要修正 Nginx 配置。
4. 搜索引擎侧:告知索引更新
在 Google Search Console 中添加 paint.net 作为新资源,并提交地址变更请求(Change of Address),声明 getpaint.net → paint.net。Bing Webmaster Tools 有类似功能。这一步配合 301 重定向,通常 2-4 周内索引会完成迁移。
22 年意味着什么
Brewster 从 2004 年开始争取这个域名。那时候 Paint.NET 还是华盛顿州立大学的一个课程项目,.net 域名注册费大约每年 15 美元,但 paint.net 已经被别人注册了。此后每年续费、每次谈判、每封邮件,都是一场漫长的消耗。
这件事对独立开发者有个清晰的提醒:项目名和域名,从一开始就要绑在一起。 如果理想域名不可用,与其用妥协前缀,不如换个项目名。getpaint.net 服务了 20 年,但那 20 年里用户始终在"到底哪个是官网"这个问题上浪费时间。
域名选择清单
启动新项目时,过一遍这个清单:
| 检查项 | 说明 |
|---|---|
项目名 + .com / .net / .org 是否可用 |
优先三选一全拿,至少拿一个 |
| 域名是否被非使用性持有 | 用 whois 查注册人,看是否有实际站点 |
| 是否需要防御性注册相近域名 | 如 paintnet.com、paint-net.org,防止混淆 |
| 域名续费是否设为自动 | 避免因忘记续费而丢失核心域名 |
| 是否在代码和文档中硬编码了旧域名 | 迁移时需要批量替换 |
快速检查域名可用性:
# 一键查询多个顶级域的可用性
for tld in com net org; do
echo -n "paint.$tld: "
whois "paint.$tld" | grep -i "no match\|not found\|available" > /dev/null \
&& echo "✅ 可能可用" \
|| echo "❌ 已注册"
done
Paint.NET 拿回域名的故事,本质上是一个关于"名字归属"的工程问题。代码可以 fork,协议可以换,但域名是互联网上最不可替代的锚点——它指向你,或者指向一个和你无关的页面。22 年很长,但结论很简单:你的名字,应该在你手里。