Shlink 是一款基于 PHP 的自托管网址缩短服务。由于个人对 PHP 存在一定心理门槛😅,此前一直未尝试部署。近期阅读项目文档后发现,它实际上支持多种 PHP Runtime(运行时):
其中,RoadRunner 是 Shlink 官方推荐的默认运行方式。它是一款由 Go 编写的 PHP 运行时,通过多个 Worker 将 Shlink 常驻于内存 (RAM) 中运行,在响应速度和整体性能方面表现良好。
Shlink 后端服务与 Web 管理后台是分离的,Web 管理面板有两种解决方案:
我选择 shlink-dashboard 作为 Web 管理面板,并使用 PostgreSQL 作为后端服务与管理面板共用的数据库。
新建 compose.yml 模板,写入
services:
db:
image: postgres:18-alpine
container_name: shlink-db
restart: unless-stopped
environment:
- POSTGRES_DB=shlink # Shlink 数据库名称
- POSTGRES_USER=shlink # 数据库用户名
- POSTGRES_PASSWORD=shlink # 数据库密码
volumes:
- ./data:/var/lib/postgresql
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro # 初始化阶段创建另一个数据库
healthcheck:
test: ["CMD-SHELL", "pg_isready -U shlink -d shlink"]
interval: 10s
timeout: 5s
retries: 5
shlink-backend:
image: shlinkio/shlink:stable
container_name: shlink-backend
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
- DB_DRIVER=postgres
- DB_HOST=db
- DB_NAME=shlink # Shlink 数据库名称
- DB_USER=shlink # 数据库用户名
- DB_PASSWORD=shlink # 数据库密码
- DEFAULT_DOMAIN=your.domain # 要绑定的短链接域名
- IS_HTTPS_ENABLED=true # 启用 HTTPS
- TIMEZONE=Asia/Shanghai
- GEOLITE_LICENSE_KEY= # [可选] MaxMind GeoLite Key
- TRUSTED_PROXIES=172.16.0.0/12
- LOGS_FORMAT=json
- DEFAULT_SHORT_CODES_LENGTH=4
- SHORT_URL_TRAILING_SLASH=true
ports:
- '127.0.0.1:8080:8080'
shlink-web:
image: shlinkio/shlink-dashboard:stable
container_name: shlink-web
user: '1000:1000'
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- '127.0.0.1:3005:3005'
environment:
SHLINK_DASHBOARD_DB_DRIVER: postgres
SHLINK_DASHBOARD_DB_HOST: db
SHLINK_DASHBOARD_DB_PORT: 5432
SHLINK_DASHBOARD_DB_NAME: dashboard # shlink-dashboard 数据库名称
SHLINK_DASHBOARD_DB_USER: shlink # 数据库用户名
SHLINK_DASHBOARD_DB_PASSWORD: shlink # 数据库密码
SHLINK_DASHBOARD_SESSION_SECRETS: secret1,secret2... # 修改会话机密,设置多个高强度随机值,半角逗号隔开
Shlink 与 shlink-dashboard 将共用同一个 PostgreSQL 容器。由于该镜像在初始化阶段默认仅创建单一数据库,我们的预期是分别为两者提供独立的数据库。
准备一个 init-db.sql,并在其中定义相应的初始化逻辑,这会在 PostgreSQL 首次启动时执行并最终创建两个可用的数据库。
CREATE DATABASE dashboard;
似乎没有必要,但为了稳妥起见,先启动数据库
sudo docker compose up -d db
低配置的 VPS 建议手动检查健康状况,确保数据库准备就绪
sudo docker compose ps db
# 或者
sudo docker compose logs -f db
现在可以启动所有服务
sudo docker compose up -d
使用 Shlink CLI 工具生成访问密钥,用于后续 Web 管理面板添加服务器
sudo docker exec -it shlink-backend shlink api-key:generate
看起来是 UUID 格式,复制保留备用

[附] Shlink CLI 命令手册建议保留备用
用法:
command [options] [arguments]
选项:
-h, --help 显示指定命令的帮助信息;如果未指定命令,则显示命令列表的帮助
--silent 不输出任何信息
-q, --quiet 仅显示错误信息,其他所有输出都会被抑制
-V, --version 显示当前应用程序的版本
--ansi|--no-ansi 强制启用(或禁用)ANSI 输出
-n, --no-interaction 不询问任何交互式问题
-v|vv|vvv, --verbose 提高输出详细程度:1 为普通输出,2 为更详细输出,3 为调试输出
可用命令:
completion 输出 shell 自动补全脚本
help 显示某个命令的帮助信息
list 列出所有可用命令
api-key
api-key:delete 按名称删除一个 API Key
api-key:disable 按名称或明文 key 禁用一个 API Key(使用明文 key 的方式已被弃用)
api-key:generate 生成一个新的有效 API Key
api-key:initial 尝试创建初始 API Key
api-key:list 列出所有可用的 API Key
api-key:rename 按名称重命名一个 API Key
domain
domain:list 列出曾被用于任意短链接的所有域名
domain:redirects 为指定域名设置特定的“未找到(404)”重定向规则
domain:visits 返回指定域名的访问记录列表
integration
integration:matomo:send-visits 将现有访问记录发送到已配置的 Matomo 实例
short-url
short-url:create 为提供的长链接生成一个短链接并返回
short-url:delete 删除一个短链接
short-url:delete-expired 删除所有被视为已过期的短链接(有效时间早于当前时间)
short-url:edit 编辑一个已有的短链接
short-url:import 允许从第三方来源导入短链接
short-url:list 列出所有短链接
short-url:manage-rules 为某个短链接设置重定向规则
short-url:parse 返回某个短代码对应的原始长链接
short-url:visits 返回指定短代码的详细访问记录信息
short-url:visits-delete 删除某个短链接的访问记录
tag
tag:delete 删除一个或多个标签
tag:list 列出现有的标签
tag:rename 重命名一个已有的标签
tag:visits 返回指定标签的访问记录列表
visit
visit:download-db 检查 GeoLite2 数据库文件是否过旧或不存在,如是则尝试下载最新版本
visit:locate 解析访问记录的来源地理位置;如有需要会自动下载或更新 GeoLite2 数据库
visit:non-orphan 返回非孤立访问记录的列表
visit:orphan 返回孤立访问记录的列表
visit:orphan-delete 删除所有孤立访问记录
为了方便管理,我将 Shlink 和 shlink-dashboard 放到同一个 Nginx 虚拟主机反向代理配置内:
server {
listen 80;
listen [::]:80;
server_name your.domain shlink-dash.your.domain;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name your.domain;
ssl_certificate /path/to/cert/your.domain.pem;
ssl_certificate_key /path/to/cert/your.domain.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ecdh_curve X25519:P-256:P-384;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE+AES128:RSA+AES128:ECDHE+AES256:RSA+AES256';
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
access_log /var/log/nginx/your.domain.access.log;
error_log /var/log/nginx/your.domain.error.log;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $realip_remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_connect_timeout 10s;
proxy_send_timeout 30s;
proxy_read_timeout 90s;
proxy_redirect off;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name shlink-dash.your.domain;
ssl_certificate /path/to/cert/shlink-dash.your.domain.pem;
ssl_certificate_key /path/to/cert/shlink-dash.your.domain.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ecdh_curve X25519:P-256:P-384;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE+AES128:RSA+AES128:ECDHE+AES256:RSA+AES256';
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
access_log /var/log/nginx/shlink-dash.your.domain.access.log;
error_log /var/log/nginx/shlink-dash.your.domain.error.log;
location / {
proxy_pass http://127.0.0.1:3005;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $realip_remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_connect_timeout 10s;
proxy_send_timeout 30s;
proxy_read_timeout 60s;
proxy_redirect off;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
}
}
检查 Nginx 配置
sudo nginx -t
重载 Nginx 配置
sudo nginx -s reload
访问 shlink-dash.your.domain 面板,默认用户名和密码都是 admin,登录后会要求修改密码。

重置密码后就进入管理后台了,点击添加服务器

输入服务器信息和访问凭据即可

现在就可以愉快的使用了。

最近需要将短链域名由 via.moe 改为 zsh.moe,从后台导出了 short_urls.csv 。
需要转换 CSV 格式:
cat << 'EOF' > convert.py
import csv
input_file = 'short_urls.csv'
output_file = 'import.csv'
# 定义 Shlink 标准列名
# 映射关系: longUrl -> Long URL, shortCode -> Short code, title -> Title, domain -> Domain, tags -> Tags
field_map = {
'longUrl': 'Long URL',
'shortCode': 'Short code',
'title': 'Title',
'domain': 'Domain',
'tags': 'Tags'
}
with open(input_file, mode='r', encoding='utf-8') as f_in:
reader = csv.DictReader(f_in)
with open(output_file, mode='w', encoding='utf-8', newline='') as f_out:
writer = csv.DictWriter(f_out, fieldnames=field_map.values())
writer.writeheader()
for row in reader:
# 提取并清理数据
new_row = {
'Long URL': row.get('longUrl', ''),
'Short code': row.get('shortCode', ''),
'Title': row.get('title', ''),
'Domain': row.get('domain', ''),
'Tags': row.get('tags', '').replace(',', '|') # 确保标签用 | 分隔
}
writer.writerow(new_row)
print(f"转换完成!已生成 {output_file}")
EOF
开始转换
python3 convert.py
设置权限
chmod 644 import.csv
编辑 compose.yml,挂载文件到容器
services:
db:
#...
shlink-backend:
image: shlinkio/shlink:stable
# ...
# 添加挂载映射
volumes:
- ./import.csv:/etc/shlink/import.csv:ro
#...
shlink-web:
#...
重新创建容器
sudo docker compose up -d
开始导入
sudo docker exec -it shlink-backend shlink short-url:import
开始导入
What is the source you want to import from:
> csv
What's the path for the CSV file you want to import:
> ./import.csv
What's the delimiter used to separate values? [Comma]:
[,] Comma
[;] Semicolon
> ,
Importing short URLs
====================
https://squoosh.app/: Imported
https://shottr.cc/: Imported
[OK] Data properly imported!
完成。
Shlink 是一款基于 PHP 的自托管网址缩短服务。由于个人对 PHP 存在一定心理门槛😅,此前一直未尝试部署。近期阅读项目文档后发现,它实际上支持多种 PHP Runtime(运行时):
其中,RoadRunner 是 Shlink 官方推荐的默认运行方式。它是一款由 Go 编写的 PHP 运行时,通过多个 Worker 将 Shlink 常驻于内存 (RAM) 中运行,在响应速度和整体性能方面表现良好。
Shlink 后端服务与 Web 管理后台是分离的,Web 管理面板有两种解决方案:
我选择 shlink-dashboard 作为 Web 管理面板,并使用 PostgreSQL 作为后端服务与管理面板共用的数据库。
新建 compose.yml 模板,写入
services:
db:
image: postgres:18-alpine
container_name: shlink-db
restart: unless-stopped
environment:
- POSTGRES_DB=shlink # Shlink 数据库名称
- POSTGRES_USER=shlink # 数据库用户名
- POSTGRES_PASSWORD=shlink # 数据库密码
volumes:
- ./data:/var/lib/postgresql
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro # 初始化阶段创建另一个数据库
healthcheck:
test: ["CMD-SHELL", "pg_isready -U shlink -d shlink"]
interval: 10s
timeout: 5s
retries: 5
shlink-backend:
image: shlinkio/shlink:stable
container_name: shlink-backend
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
- DB_DRIVER=postgres
- DB_HOST=db
- DB_NAME=shlink # Shlink 数据库名称
- DB_USER=shlink # 数据库用户名
- DB_PASSWORD=shlink # 数据库密码
- DEFAULT_DOMAIN=your.domain # 要绑定的短链接域名
- IS_HTTPS_ENABLED=true # 启用 HTTPS
- TIMEZONE=Asia/Shanghai
- GEOLITE_LICENSE_KEY= # [可选] MaxMind GeoLite Key
- TRUSTED_PROXIES=172.16.0.0/12
- LOGS_FORMAT=json
- DEFAULT_SHORT_CODES_LENGTH=4
- SHORT_URL_TRAILING_SLASH=true
ports:
- '127.0.0.1:8080:8080'
shlink-web:
image: shlinkio/shlink-dashboard:stable
container_name: shlink-web
user: '1000:1000'
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- '127.0.0.1:3005:3005'
environment:
SHLINK_DASHBOARD_DB_DRIVER: postgres
SHLINK_DASHBOARD_DB_HOST: db
SHLINK_DASHBOARD_DB_PORT: 5432
SHLINK_DASHBOARD_DB_NAME: dashboard # shlink-dashboard 数据库名称
SHLINK_DASHBOARD_DB_USER: shlink # 数据库用户名
SHLINK_DASHBOARD_DB_PASSWORD: shlink # 数据库密码
SHLINK_DASHBOARD_SESSION_SECRETS: secret1,secret2... # 修改会话机密,设置多个高强度随机值,半角逗号隔开
Shlink 与 shlink-dashboard 将共用同一个 PostgreSQL 容器。由于该镜像在初始化阶段默认仅创建单一数据库,我们的预期是分别为两者提供独立的数据库。
准备一个 init-db.sql,并在其中定义相应的初始化逻辑,这会在 PostgreSQL 首次启动时执行并最终创建两个可用的数据库。
CREATE DATABASE dashboard;
似乎没有必要,但为了稳妥起见,先启动数据库
sudo docker compose up -d db
低配置的 VPS 建议手动检查健康状况,确保数据库准备就绪
sudo docker compose ps db
# 或者
sudo docker compose logs -f db
现在可以启动所有服务
sudo docker compose up -d
使用 Shlink CLI 工具生成访问密钥,用于后续 Web 管理面板添加服务器
sudo docker exec -it shlink-backend shlink api-key:generate
看起来是 UUID 格式,复制保留备用

[附] Shlink CLI 命令手册建议保留备用
用法:
command [options] [arguments]
选项:
-h, --help 显示指定命令的帮助信息;如果未指定命令,则显示命令列表的帮助
--silent 不输出任何信息
-q, --quiet 仅显示错误信息,其他所有输出都会被抑制
-V, --version 显示当前应用程序的版本
--ansi|--no-ansi 强制启用(或禁用)ANSI 输出
-n, --no-interaction 不询问任何交互式问题
-v|vv|vvv, --verbose 提高输出详细程度:1 为普通输出,2 为更详细输出,3 为调试输出
可用命令:
completion 输出 shell 自动补全脚本
help 显示某个命令的帮助信息
list 列出所有可用命令
api-key
api-key:delete 按名称删除一个 API Key
api-key:disable 按名称或明文 key 禁用一个 API Key(使用明文 key 的方式已被弃用)
api-key:generate 生成一个新的有效 API Key
api-key:initial 尝试创建初始 API Key
api-key:list 列出所有可用的 API Key
api-key:rename 按名称重命名一个 API Key
domain
domain:list 列出曾被用于任意短链接的所有域名
domain:redirects 为指定域名设置特定的“未找到(404)”重定向规则
domain:visits 返回指定域名的访问记录列表
integration
integration:matomo:send-visits 将现有访问记录发送到已配置的 Matomo 实例
short-url
short-url:create 为提供的长链接生成一个短链接并返回
short-url:delete 删除一个短链接
short-url:delete-expired 删除所有被视为已过期的短链接(有效时间早于当前时间)
short-url:edit 编辑一个已有的短链接
short-url:import 允许从第三方来源导入短链接
short-url:list 列出所有短链接
short-url:manage-rules 为某个短链接设置重定向规则
short-url:parse 返回某个短代码对应的原始长链接
short-url:visits 返回指定短代码的详细访问记录信息
short-url:visits-delete 删除某个短链接的访问记录
tag
tag:delete 删除一个或多个标签
tag:list 列出现有的标签
tag:rename 重命名一个已有的标签
tag:visits 返回指定标签的访问记录列表
visit
visit:download-db 检查 GeoLite2 数据库文件是否过旧或不存在,如是则尝试下载最新版本
visit:locate 解析访问记录的来源地理位置;如有需要会自动下载或更新 GeoLite2 数据库
visit:non-orphan 返回非孤立访问记录的列表
visit:orphan 返回孤立访问记录的列表
visit:orphan-delete 删除所有孤立访问记录
为了方便管理,我将 Shlink 和 shlink-dashboard 放到同一个 Nginx 虚拟主机反向代理配置内:
server {
listen 80;
listen [::]:80;
server_name your.domain shlink-dash.your.domain;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name your.domain;
ssl_certificate /path/to/cert/your.domain.pem;
ssl_certificate_key /path/to/cert/your.domain.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ecdh_curve X25519:P-256:P-384;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE+AES128:RSA+AES128:ECDHE+AES256:RSA+AES256';
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
access_log /var/log/nginx/your.domain.access.log;
error_log /var/log/nginx/your.domain.error.log;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $realip_remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_connect_timeout 10s;
proxy_send_timeout 30s;
proxy_read_timeout 90s;
proxy_redirect off;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name shlink-dash.your.domain;
ssl_certificate /path/to/cert/shlink-dash.your.domain.pem;
ssl_certificate_key /path/to/cert/shlink-dash.your.domain.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ecdh_curve X25519:P-256:P-384;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE+AES128:RSA+AES128:ECDHE+AES256:RSA+AES256';
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
access_log /var/log/nginx/shlink-dash.your.domain.access.log;
error_log /var/log/nginx/shlink-dash.your.domain.error.log;
location / {
proxy_pass http://127.0.0.1:3005;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $realip_remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_connect_timeout 10s;
proxy_send_timeout 30s;
proxy_read_timeout 60s;
proxy_redirect off;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
}
}
检查 Nginx 配置
sudo nginx -t
重载 Nginx 配置
sudo nginx -s reload
访问 shlink-dash.your.domain 面板,默认用户名和密码都是 admin,登录后会要求修改密码。

重置密码后就进入管理后台了,点击添加服务器

输入服务器信息和访问凭据即可

现在就可以愉快的使用了。

最近需要将短链域名由 via.moe 改为 zsh.moe,从后台导出了 short_urls.csv 。
需要转换 CSV 格式:
cat << 'EOF' > convert.py
import csv
input_file = 'short_urls.csv'
output_file = 'import.csv'
# 定义 Shlink 标准列名
# 映射关系: longUrl -> Long URL, shortCode -> Short code, title -> Title, domain -> Domain, tags -> Tags
field_map = {
'longUrl': 'Long URL',
'shortCode': 'Short code',
'title': 'Title',
'domain': 'Domain',
'tags': 'Tags'
}
with open(input_file, mode='r', encoding='utf-8') as f_in:
reader = csv.DictReader(f_in)
with open(output_file, mode='w', encoding='utf-8', newline='') as f_out:
writer = csv.DictWriter(f_out, fieldnames=field_map.values())
writer.writeheader()
for row in reader:
# 提取并清理数据
new_row = {
'Long URL': row.get('longUrl', ''),
'Short code': row.get('shortCode', ''),
'Title': row.get('title', ''),
'Domain': row.get('domain', ''),
'Tags': row.get('tags', '').replace(',', '|') # 确保标签用 | 分隔
}
writer.writerow(new_row)
print(f"转换完成!已生成 {output_file}")
EOF
开始转换
python3 convert.py
设置权限
chmod 644 import.csv
编辑 compose.yml,挂载文件到容器
services:
db:
#...
shlink-backend:
image: shlinkio/shlink:stable
# ...
# 添加挂载映射
volumes:
- ./import.csv:/etc/shlink/import.csv:ro
#...
shlink-web:
#...
重新创建容器
sudo docker compose up -d
开始导入
sudo docker exec -it shlink-backend shlink short-url:import
开始导入
What is the source you want to import from:
> csv
What's the path for the CSV file you want to import:
> ./import.csv
What's the delimiter used to separate values? [Comma]:
[,] Comma
[;] Semicolon
> ,
Importing short URLs
====================
https://squoosh.app/: Imported
https://shottr.cc/: Imported
[OK] Data properly imported!
完成。