站长为什么需要一个自己的短链接服务
短链接这个东西,大多数人第一次接触是在微博、短信或者二维码里——一条长长的网址被压成短短几个字符。但作为一个做站的人,自己搭一套短链服务,理由和"发微博好看"完全无关,而是实打实的运营需求:
第一,统计数据自主可控。你用第三方短链服务(bit.ly 之类),点击数据存在别人的服务器上,哪天服务商改了政策、加了收费、或者干脆关停,你的历史数据就没了。自建短链,每一次点击都落在你自己的数据库里,你能看来源、设备、地域、时间分布,且永久保存。
第二,域名资产和品牌。用自己域名的短链(比如 `s.你的站.com/abc`),点击者能看出这是你的链接,可信度比陌生的第三方短链高很多,也不会被部分平台当成垃圾链接屏蔽。
第三,可随时改目的地。这一点最实用:你把一张印了二维码的传单发出去了,或者一段带短链的文案被人转发了,事后想换个落地页——短链的目标 URL 在你手里,随时改,已发出的链接不会失效。第三方服务往往要付费才给这个能力。
第四,可控性。你可以给短链加密码、设过期时间、限制访问地区、甚至按时间自动下线,这些在自建方案里都是配置文件里一两行的事。
这篇文章用两个主流方案把短链服务跑起来:轻量的 YOURLS(PHP,适合已有 LNMP 环境的站长)和功能更完整的 Shlink(Docker 部署,自带 REST API 和漂亮的统计界面)。两条路都走到能用,重点是讲清楚 Nginx 反代、数据备份和几个容易踩的坑。
方案一:YOURLS——最轻的 PHP 短链,老机器也能跑
YOURLS 是一个老牌的 PHP 短链程序,依赖极小,扔进任何 LNMP 环境就能跑,特别适合那些机器配置不高、不想引入 Docker 的站长。
先在站点目录下拉取源码,然后准备一个专属的数据库:
cd /var/www
git clone https://github.com/YOURLS/YOURLS.git shortlink
cd shortlink
cp user/config-sample.php user/config.php编辑 `user/config.php`,填数据库信息和你的短链域名:
define( 'YOURLS_DB_USER', 'shortlink' );
define( 'YOURLS_DB_PASS', '你的强密码' );
define( 'YOURLS_DB_NAME', 'shortlink' );
define( 'YOURLS_DB_HOST', 'localhost' );
// 短链的对外域名,必须和真实访问地址一致
define( 'YOURLS_SITE', 'https://s.example.com' );
// 后台密码的哈希,用官方脚本生成,不要手动填明文
define( 'YOURLS_USER', 'admin' );
define( 'YOURLS_PASS', '把这里换成哈希值' );数据库和用户建好后,浏览器访问 `https://s.example.com/admin/` 会引导你完成建表(点击 "Install YOURLS" 按钮即可)。这里有个新手常犯的错:`YOURLS_SITE` 一定要写成最终的 HTTPS 地址,包括协议头。如果先填了 http、后来又上了 https,已经生成的短链会因为域名不匹配而跳错。
生成后台密码哈希用官方提供的方式最稳妥:
php -r 'echo password_hash("你的明文密码", PASSWORD_DEFAULT);'把输出的哈希整段粘进 `YOURLS_PASS`。YOURLS 支持密码哈希,比明文安全,就算配置文件泄露也拿不到明文密码。
Nginx 反代与伪静态:短链能打开的关键
短链的原理是"路径即短码"——访问 `s.example.com/abc` 时,Nginx 要把这个不存在的物理路径交给 YOURLS 的 `yourls-loader.php` 去查库。所以必须配好 rewrite,否则会直接 404。
server {
listen 443 ssl http2;
server_name s.example.com;
root /var/www/shortlink;
index index.php;
location / {
try_files $uri $uri/ /yourls-loader.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# 禁止别人直接访问后台配置文件
location ~ /user/ {
deny all;
}
}关键就是那行 `try_files ... /yourls-loader.php`:先尝试真实文件,找不到就把请求交给加载器去查短码。`location ~ /user/` 把配置目录挡在外面,防止有人直接下载读到数据库密码——很多 YOURLS 被入侵就是栽在这一步。
配置好之后,做一次跳转测试,确认短码真的能解析:
curl -sI https://s.example.com/abc | head -5
# 期望看到 HTTP/2 301 或 302,Location 指向目标地址如果返回 404,九成是 `try_files` 那行写错或 Nginx 没重载;如果返回 200 但页面是 YOURLS 首页,说明短码其实没被识别,检查 `YOURLS_SITE` 和访问域名是否一致。
方案二:Shlink——自带 API 和统计面板的完整方案
如果你希望短链服务更"现代化"一些——有 REST API 可以程序化创建短链、有统计图表、支持多域名、能自定义访问规则——那 Shlink 是更好的选择。它用 Docker 部署,自带一个 SQLite 或 MySQL 存储,还有一个独立的 Web 管理界面。
# docker-compose.yml
version: "3.9"
services:
shlink:
image: shlinkio/shlink:stable
restart: unless-stopped
environment:
DEFAULT_DOMAIN: s.example.com
IS_HTTPS_ENABLED: "true"
# API 密钥,客户端创建短链时要带这个
INITIAL_API_KEY: "在这里填一个随机的长字符串"
# 用 SQLite 最省事,数据落在挂载卷里
DB_DRIVER: sqlite
volumes:
- ./data:/etc/shlink/data
ports:
- "127.0.0.1:8080:8080"
shlink-web:
image: shlinkio/shlink-web-client:stable
restart: unless-stopped
ports:
- "127.0.0.1:8081:80"
depends_on:
- shlink注意这里两个服务都只监听 `127.0.0.1`,不直接对公网开放——由 Nginx 在前面统一反代和做 HTTPS,这是所有自建服务都该遵循的安全习惯。
Shlink 的 API 用起来很顺手,创建短链就是一次带鉴权头的 POST:
curl -X POST "https://s.example.com/rest/v3/short-urls" \
-H "X-Api-Key: 你的API密钥" \
-H "Content-Type: application/json" \
-d '{"longUrl": "https://www.example.com/very/long/path",
"customSlug": "promo1",
"validUntil": "2026-12-31T23:59:59+00:00",
"maxVisits": 1000}'`customSlug` 是你自己指定的短码(不填就随机生成),`validUntil` 让链接到期自动失效,`maxVisits` 限制最大点击次数。这些参数在 Nginx 反代方案里要手写逻辑,Shlink 直接内置了——这就是它比 YOURLS 更适合"要拿短链做活动推广"的场景的原因。
Shlink 的反代配置要点和 YOURLS 类似,但多一层:要把 `/rest/` 和后台路径转发到对应服务,同时确保 `X-Forwarded-Proto` 头传对,否则 Shlink 内部会以为自己在 HTTP 下,生成出 http 的短链。
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; # 这一行不能漏
}漏掉 `X-Forwarded-Proto` 是 Shlink 自建最常见的坑:生成出来的短链是 http 开头,用户点开会被浏览器警告"不安全",排查半天才发现是反代头没传。
短链的数据备份与迁移
短链是典型的"数据虽小但丢了很麻烦"的服务——里面的每一条都对应着一个已经发出去的二维码或外链。备份策略因方案而异:
YOURLS 的数据全在一个 MySQL 库里,直接逻辑备份即可:
mysqldump --single-transaction shortlink > shortlink-$(date +%F).sqlShlink 如果用 SQLite,整份数据就是一个文件,连同配置目录一起打包:
tar czf shlink-backup-$(date +%F).tar.gz ./data docker-compose.yml关键在于定期验证恢复,而不是只备份。我踩过一个坑:一直备份,但从来没过恢复演练,真要迁移机器时才发现备份文件的数据库版本和新装的 MariaDB 不兼容,导入报错。正确做法是每季度在测试环境真恢复一次,确认导入后短链能正常跳转。备份不等于恢复能力,这一点值得反复强调。
防盗链与滥用防护:别让短链服务被人拿去做坏事
公开可用的短链服务有个隐形风险:一旦被搜索引擎收录或被坏人发现,就会有人拿你的域名生成指向钓鱼站、菠菜站的短链。出事之后流量是你的、域名是你的,背锅的却是你。所以自建短链务必做几件事。
一、限制短链创建。 YOURLS 默认任何人访问后台都能注册账号、创建短链。在 `config.php` 里关掉公开注册:
define( 'YOURLS_PRIVATE', true ); // 整个站点需要登录才能用
define( 'YOURLS_PRIVATE_INFOS', true ); // 短链信息页也设为私有
// 可选的域名白名单,只允许缩短你自己信任的域名
$yourls_allowedprotocols = array( 'http', 'https' );二、禁止机器人抓取和泛解析。 在 Nginx 里加一个 `robots.txt`,避免短链页面被搜索引擎大量索引——短链域名本身不该有 SEO 价值,被收录反而是负担。同时关掉短链域名的泛解析,防止有人用你的域名做镜像。
location = /robots.txt {
add_header Content-Type text/plain;
# 用 echo 输出两行,避免在配置里内嵌换行转义
return 200 "User-agent: * Disallow: /";
}三、给 API 密钥和后台加上限流。 短链服务的创建接口是被滥用的重灾区,用 Nginx 的 `limit_req` 限速,能挡掉绝大部分脚本化的批量创建:
limit_req_zone $binary_remote_addr zone=shortapi:10m rate=5r/m;
location /rest/ {
limit_req zone=shortapi burst=3 nodelay;
proxy_pass http://127.0.0.1:8080;
}限制每分钟 5 次创建请求,对正常运营完全够用,对恶意批量创建则是致命的。
真实复盘:一次短链域名被墙带来的连锁反应
说个教训。曾经我把短链服务挂在一个跟主站不同的域名上,图的是"干净"。结果某次做推广,短链域名被发到了一个被严重滥用、平台风控极强的环境里,第二天就发现这个短链域名在部分网络下打不开——不是被墙,是被某些运营商/拦截系统基于域名信誉给拦了。更麻烦的是,所有已经印出去的材料、已经发出的链接,用的都是这个域名,改都改不了。
补救过程本身也是个技术活:先把短链域名切到主域的一个子域(比如从独立的 `xxx.link` 换到 `s.主站.com`),利用主站域名已有的信誉;同时在旧的短链域名上保留 301,按短码映射到新域名,保证旧链接不失效。这个"双域名并存 + 301 映射"其实很快就能做——因为短码和目标 URL 的映射关系始终在你自己数据库里,这正是自建短链最大的底气:域名可以换,数据不会丢,映射关系可以整体迁移。
事后我的做法是:新短链一律用主站的子域,独立域名只在确实需要品牌独立的场景才用;同时给短链域名单独配一个监控探针,一旦全国多点探测出现大面积失败就告警。运营工具的稳定性,很多时候不取决于技术,而取决于你有没有为"它可能被外部因素干掉"提前留好后路。
小结
自建短链服务对个人站长不是必需品,一旦你开始做推广、发二维码、投文案,它就会从"可选项"变成"该有的基础设施"。方案选择上:机器上已经跑着 LNMP、追求轻量,就用 YOURLS,一个下午能上线;需要 API、统计面板、多域名和访问规则,就用 Shlink(Docker)。两条路共同的几个要点——反代传对 `X-Forwarded-Proto`、用 HTTPS、关掉公开注册、加限流、定期验证恢复——做到位,你的短链就是一个自主可控、随叫随到、还能随时改目的地的运营利器。