GoToSocial 0.22.3 常用 CLI 命令与 API 详解

GoToSocial 0.22.3 常用 CLI 命令与 REST API 详解:server/database/admin 等五大子命令与账号管理实测,Mastodon 兼容 API 的 OAuth 认证、发帖、时间线、媒体上传全流程 curl 实测。

GoToSocialGoToSocialMastodonGolang2026/10/30

GoToSocial 0.22.3 常用 CLI 命令与 API 详解

目标:把 GoToSocial v0.22.3 的运维入口一次讲全——gotosocial 命令行工具(server/database/migrations/debug/admin 五大子命令树)与 Mastodon 兼容 REST API(应用注册、OAuth 换 token、发帖、时间线、媒体上传、实例信息),全部命令与 JSON 回显在 Ubuntu 22.04.5 实测环境(/gotosocial、端口 8147、演示账号 admin)逐条验证。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS x86_64
  • 软件版本:GoToSocial 0.22.3+git-5a6c8e2(安装见《Ubuntu 22.04 安装 GoToSocial 0.22.3 指南》)
  • 实例形态:本地实例模式(host: localhost、HTTP、端口 8147、SQLite、本地存储)
  • 演示账号:admin / Q1w2E3r4T5!(CLI 创建并已 promote 为管理员)
  • API 基址:http://localhost:8147(Mastodon 兼容 API 前缀 /api/v1,OAuth 前缀 /oauth)
  • 客户端工具:curl 7.81.0(系统自带)

二、工具概览

GoToSocial 的运维入口只有两样:单二进制自带的 CLI(服务启动、数据库、迁移、调试、账号管理全在这一个命令里)与 REST API(Mastodon 兼容,Web 设置面板与第三方客户端都走它)。CLI 结构(gotosocial --help 实测首段):

GoToSocial - a fediverse social media server

Usage:
  gotosocial [command]

Available Commands:
  admin       gotosocial admin-related tasks
  completion  Generate the autocompletion script for the specified shell
  database    gotosocial database-releated tasks
  debug       gotosocial debug-related tasks
  help        Help about any command
  migrations  gotosocial migrations-related tasks
  server      gotosocial server-related tasks

Flags:
      --account-domain string     Domain to use in account names …
      --bind-address string       Bind address to use for the GoToSocial server …(default "0.0.0.0")
      …(全局 flag 与全部配置键一一对应)

💡 技术拓展:联邦社交服务器的 API 兼容策略不止一种。主流对比——

策略代表特点
兼容 Mastodon REST APIGoToSocial、Akkoma、Pleroma直接复用 Mastodon 客户端生态
自有 API + 兼容层Misskey自家 API 为主,Mastodon 兼容是子集
仅 ActivityPub早期实现无客户端 API,功能受限

GoToSocial 全量实现 Mastodon 客户端 API(含 OAuth 流程),本文 API 章节即按该口径实测。

三、前置条件

  • 服务已启动并监听:systemctl is-active gotosocial 为 active,curl -s -o /dev/null -w "%{http_code}" http://localhost:8147/ 返回 200;
  • 至少存在一个本地账号:admin account list 能看到记录(创建方法见安装指南 7.1);
  • CLI 命令统一在 /gotosocial 目录以配置文件参数执行:./gotosocial --config-path ./config.yaml <子命令>(systemd 场景亦同,服务以 gotosocial 用户运行,CLI 操作建议 su -s /bin/bash gotosocial 或保证对该用户数据目录的写权限)。

四、主命令详解

gotosocial 根命令下五个功能子命令,逐一实测。

4.1 server:服务启停与维护模式

./gotosocial server --help

实测回显:

gotosocial server-related tasks

Usage:
  gotosocial server [command]

Available Commands:
  maintenance start the gotosocial server in maintenance mode (returns 503 for almost all requests)
  start       start the gotosocial server
  • server start:前台启动服务(systemd 单元的 ExecStart 即此命令);
  • server maintenance:以维护模式启动,除探活外全部请求返回 503,用于迁移数据库前挂公告页。日常启停用 systemd:
systemctl start gotosocial && systemctl is-active gotosocial

实测回显:

active

4.2 database:数据库连通与专属任务

./gotosocial --config-path ./config.yaml database ping

实测回显(输出节选,INFO 日志 + ping 确认):

timestamp="29/10/2026 17:45:11.495" func=bundb.sqliteConn level=INFO msg="connected to SQLITE database with address file:/gotosocial/sqlite.db?_pragma=busy_timeout%281800000%29&_pragma=journal_mode%28WAL%29&_pragma=synchronous%28NORMAL%29&_pragma=cache_size%28-8192%29&_txlock=immediate"
timestamp="29/10/2026 17:45:11.496" func=bundb.doMigration level=INFO msg="there are no new migrations to run"
timestamp="29/10/2026 17:45:11.496" func=database.Ping.func1 level=INFO msg=ping

服务运行中执行 ping 亦成功(SQLite WAL 读写并发),输出末尾进程以 done! exiting... 退出。database sqlite 子命令提供 SQLite 专属维护任务(vacuum/analyze 类);切 PostgreSQL 后同命令探测 PG 连通性。

4.3 migrations:手动跑迁移

./gotosocial migrations --help

实测回显:

gotosocial migrations-related tasks

Usage:
  gotosocial migrations [command]

Available Commands:
  run         starts and stops the database, running any outstanding migrations

migrations run 会临时拉起数据库服务执行未完成的迁移再退出。日常无需手动执行——server start 启动时自动迁移(日志 doMigration),它主要在升级排障时使用。

4.4 debug:配置与调试

./gotosocial debug --help

实测回显:

gotosocial debug-related tasks

Usage:
  gotosocial debug [command]

Available Commands:
  config      print the collated config (derived from env, flag, and config file) to stdout

debug config 把 flag/env/文件/默认值四级合并后的生效配置以 JSON 打印(249 键),是配置排障第一工具,用法与回显见《GoToSocial 0.22.3 配置参数详解》第三章。

五、admin 命令详解

管理员的日常入口,覆盖账号、媒体、状态与数据导入导出(gotosocial admin --help 实测):

Available Commands:
  account     admin commands related to local (this instance) accounts
  export      export data from the database to file at the given path
  import      import data from a file into the database
  media       admin commands related to stored media / emojis
  statuses    admin commands related to stored statuses

5.1 admin account:本地账号管理

./gotosocial admin account --help

实测回显(9 个子命令):

Available Commands:
  confirm     confirm an existing local account manually, thereby skipping email confirmation
  create      create a new local account
  demote      demote a local account from admin to normal user
  disable     set 'disabled' to true on a local account to prevent it from signing in or posting etc, but don't delete anything
  disable-2fa disable 2fa for the given local account
  enable      undo a previous disable command by setting 'disabled' to false on a local account
  list        list all existing local accounts
  password    set a new password for the given local account
  promote     promote a local account to admin

实例初始化三连(创建→确认→提权)与状态核对:

cd /gotosocial
./gotosocial --config-path ./config.yaml admin account create --username admin --email admin@localhost.localdomain --password 'Q1w2E3r4T5!'
./gotosocial --config-path ./config.yaml admin account confirm --username admin
./gotosocial --config-path ./config.yaml admin account promote --username admin
./gotosocial --config-path ./config.yaml admin account list 2>/dev/null

实测回显(list):

user  account                    approved admin moderator suspended confirmed
admin 01GCAFW13JWEEZ9BG56T9B4CQQ yes      yes   yes       no        yes

列含义:account 为账号 ULID;approved 注册审核、admin/moderator 角色位、suspended 停用位、confirmed 邮箱确认位。disable 与 suspended 的区别是前者仅禁登录禁发帖、保留全部数据,可随时 enable 恢复。

5.2 admin media:媒体巡检与清理

./gotosocial admin media --help

实测回显:

Available Commands:
  list-attachments list local, remote, or all attachments
  list-emojis      list local, remote, or all emojis
  prune            admin commands for pruning media from storage

巡检本地附件(prune 下含孤儿文件与过期远端缓存清理任务,配合 config 的 media-cleanup-cron 使用):

./gotosocial --config-path ./config.yaml admin media list-attachments --local-only 2>/dev/null | tail -3

实测回显(实测环境已有 1 个测试附件):

01M64C6RR6PEZSFTTW3ESGYN4V  image/png  admin  实测上传的红绿渐变 64x64 PNG

5.3 admin export / import:数据搬家

admin export --path <file> 把数据库数据导出为 JSON 文件,admin import --path <file> 反向导入,配合 SQLite 文件拷贝即构成实例迁移的最小方案。export 的参数面(实测 --help):

Flags:
      --path string   the path of the file to import from/export to

六、REST API 详解

API 全部走 http://localhost:8147。认证链路是 Mastodon 标准 OAuth2:注册应用 → 用户授权 → 换 access_token → Bearer 调用,以下逐步实测。

6.1 注册应用(POST /api/v1/apps)

curl -s -X POST http://localhost:8147/api/v1/apps \
  -H 'Content-Type: application/json' \
  -d '{"client_name":"quzuo-cli-test","redirect_uris":"urn:ietf:wg:oauth:2.0:oob","scopes":"read write follow push","website":"https://localhost.localdomain"}'

实测回显:

{
    "id": "01M64C21WH4GSZF4G04YRSGSVR",
    "created_at": "2026-10-29T17:41:54.193Z",
    "name": "quzuo-cli-test",
    "website": "https://localhost.localdomain",
    "redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
    "redirect_uris": ["urn:ietf:wg:oauth:2.0:oob"],
    "client_id": "01ZCBZDVVHWREYXR50E52WWSDY",
    "client_secret": "71a7df30-ccb1-440d-95f5-bee24e4296c0",
    "vapid_key": "BADRE6FPArd4KmMrT-0ZN5KbVjqAlthLCQf58VpeS7B8rChvwaROrGUOnTr-871fhVpJ0qAJSSktYD04JgwkJTc",
    "scopes": ["read","write","follow","push"]
}

urn:ietf:wg:oauth:2.0:oob 是带外授权回调(授权码直接显示在页面上,便于 CLI 场景);client_id/client_secret 为本测试实例的临时凭据,读者环境以实际返回为准。

6.2 用户授权拿授权码(/oauth/authorize 四步)

授权页依赖会话状态,curl 复现需严格按四步走(实测全通过):

# 第 1 步:带参数访问授权页,拿到 303 跳登录并初始化会话
curl -s -c /tmp/c.txt -o /dev/null -w '%{http_code} -> %{redirect_url}\n' \
  'http://localhost:8147/oauth/authorize?client_id=01ZCBZDVVHWREYXR50E52WWSDY&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=read+write+follow+push'

实测回显:

303 -> http://localhost:8147/auth/sign_in
# 第 2 步:提交登录表单,302 回授权页
curl -s -b /tmp/c.txt -c /tmp/c.txt -o /dev/null -w '%{http_code} -> %{redirect_url}\n' \
  -d 'username=admin@localhost.localdomain&password=Q1w2E3r4T5!' \
  http://localhost:8147/auth/sign_in

实测回显:

302 -> http://localhost:8147/oauth/authorize
# 第 3 步:带会话访问授权页,返回 Allow 确认表单
curl -s -b /tmp/c.txt -c /tmp/c.txt 'http://localhost:8147/oauth/authorize?client_id=01ZCBZDVVHWREYXR50E52WWSDY&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=read+write+follow+push' \
  | grep -oE '<form[^>]*>|<button[^>]*>[^<]*'

实测回显:

<form action="/oauth/authorize" method="POST">
<button type="submit" class="btn btn-success">Allow
# 第 4 步:提交 Allow,302 的 Location 里就是带外授权码
curl -s -b /tmp/c.txt -D - -o /dev/null -X POST http://localhost:8147/oauth/authorize | grep -i location

实测回显:

Location: /oauth/oob?code=MWQ3MMVHMWMTMJCWZI0ZNJQ2LTGZNDKTYZVJNJI2N2FJNTI2

⚠️ 注意:跳过第 1 步、拿已登录会话直接访问授权页会得到 500,日志报 key redirect_uri not found in session——授权参数必须先经过第 1 步写入会话。

6.3 换取 access_token(POST /oauth/token)

curl -s -X POST http://localhost:8147/oauth/token \
  -H 'Content-Type: application/json' \
  -d '{"redirect_uri":"urn:ietf:wg:oauth:2.0:oob","client_id":"01ZCBZDVVHWREYXR50E52WWSDY","client_secret":"71a7df30-ccb1-440d-95f5-bee24e4296c0","grant_type":"authorization_code","code":"MWQ3MMVHMWMTMJCWZI0ZNJQ2LTGZNDKTYZVJNJI2N2FJNTI2"}'

实测回显:

{
    "access_token": "NDRLNJRKNJKTZDKYMY0ZODY5LTHKNDQTZDU4MTVIYTZIN2E0",
    "created_at": 1793295795,
    "scope": "read write follow push",
    "token_type": "Bearer"
}

6.4 验证凭据(GET /api/v1/accounts/verify_credentials)

TOKEN=NDRLNJRKNJKTZDKYMY0ZODY5LTHKNDQTZDU4MTVIYTZIN2E0
curl -s -H "Authorization: Bearer $TOKEN" http://localhost:8147/api/v1/accounts/verify_credentials | head -c 400; echo

实测回显(节选):

{
    "id": "01GCAFW13JWEEZ9BG56T9B4CQQ",
    "username": "admin",
    "acct": "admin",
    "display_name": "admin",
    "locked": true,
    "discoverable": false,
    "created_at": "2026-10-29T17:41:36.000Z",
    "url": "http://localhost/@admin",
    "avatar": "http://localhost/assets/default_avatars/GoToSocial_icon1.webp",
    "followers_count": 0,
    "following_count": 0,
    "statuses_count": 0,

不带 token 调用受保护接口得到明确 401:

curl -s -o /dev/null -w '%{http_code} ' http://localhost:8147/api/v1/timelines/home; curl -s http://localhost:8147/api/v1/timelines/home; echo

实测回显:

401 {"error":"Unauthorized: token not supplied"}

6.5 发帖(POST /api/v1/statuses)

curl -s -X POST http://localhost:8147/api/v1/statuses \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"status":"Hello from GoToSocial v0.22.3 on Ubuntu 22.04! 这是一条 API 实测帖。#gotosocial","visibility":"public"}' | head -c 500; echo

实测回显(节选,hashtag 已被解析为可点击话题链接):

{
    "id": "01M64C4XWNTGE9ZGZWDDBHJ46E",
    "created_at": "2026-10-29T17:43:28.406Z",
    "visibility": "public",
    "language": "en",
    "uri": "http://localhost/users/admin/statuses/01M64C4XWNTGE9ZGZWDDBHJ46E",
    "url": "http://localhost/@admin/statuses/01M64C4XWNTGE9ZGZWDDBHJ46E",
    "content": "<p>Hello from GoToSocial v0.22.3 on Ubuntu 22.04! 这是一条 API 实测帖。<a href=\"http://localhost/tags/gotosocial\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>gotosocial</span></a></p>",

visibility 支持 public/unlisted/private/direct 四档,与 Mastodon 语义一致。

6.6 时间线(GET /api/v1/timelines/home)

curl -s -H "Authorization: Bearer $TOKEN" 'http://localhost:8147/api/v1/timelines/home?limit=5' \
  | python3 -c "import json,sys; d=json.load(sys.stdin); print('count:', len(d)); print('first:', d[0]['content'][:60])"

实测回显:

count: 1
first: <p>Hello from GoToSocial v0.22.3 on Ubuntu 22.04! 这是一条 API 实测帖。<a h

刚发的帖子实时出现在 home 时间线;limit/max_id/since_id 分页参数与 Mastodon 约定一致。公开时间线受 instance-expose-public-timeline 配置控制(默认关闭,未授权访问被拒)。

6.7 媒体上传与带图发帖(POST /api/v1/media)

curl -s -X POST http://localhost:8147/api/v1/media \
  -H "Authorization: Bearer $TOKEN" \
  -F 'file=@/gotosocial/test.png;type=image/png' \
  -F 'description=实测上传的红绿渐变 64x64 PNG' | head -c 430; echo

实测回显(节选,自动生成原图与缩略图两级 URL):

{
    "id": "01M64C6RR6PEZSFTTW3ESGYN4V",
    "type": "image",
    "url": "http://localhost/fileserver/01GCAFW13JWEEZ9BG56T9B4CQQ/attachment/original/01M64C6RR6PEZSFTTW3ESGYN4V.png",
    "text_url": "http://localhost/fileserver/01GCAFW13JWEEZ9BG56T9B4CQQ/attachment/original/01M64C6RR6PEZSFTTW3ESGYN4V.png",
    "preview_url": "http://localhost/fileserver/01GCAFW13JWEEZ9BG56T9B4CQQ/attachment/small/01M64C6RR6PEZSFTTW3ESGYN4V.jpeg",
    "meta": {
        "original": {"width": 64, "height": 64, "size": "64x64", "aspect": 1},
        "small": {"width": 64, "height": 64, "size": "64x64", "aspect": 1}

上传成功后把 media_ids 带进发帖请求:

curl -s -X POST http://localhost:8147/api/v1/statuses \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"status":"媒体接口实测:配图发帖成功","media_ids":["01M64C6RR6PEZSFTTW3ESGYN4V"],"visibility":"public"}' \
  | python3 -c "import json,sys; d=json.load(sys.stdin); print('id:', d['id']); print('media:', [(a['id'], a['type']) for a in d['media_attachments']])"

实测回显:

id: 01M64C73YV42Z4NSFNRQSNADV2
media: [('01M64C6RR6PEZSFTTW3ESGYN4V', 'image')]

⚠️ 注意:损坏的图片文件会得到 422 {"error":"Unprocessable Entity: error processing media"},服务端日志可见具体解码错误(实测传坏 PNG 报 png: invalid format: bad filter type);媒体处理由内置 WASM ffmpeg 完成,无需宿主机安装 ffmpeg。

6.8 实例信息与健康检查

curl -s http://localhost:8147/api/v1/instance | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['domain'], '|', d['title'], '|', d['version'])"
curl -s -o /dev/null -w 'livez -> %{http_code}\n' http://localhost:8147/livez
curl -s -o /dev/null -w 'readyz -> %{http_code}\n' http://localhost:8147/readyz
curl -s -o /dev/null -w 'nodeinfo/2.0 -> %{http_code}\n' http://localhost:8147/nodeinfo/2.0
curl -s -o /dev/null -w 'GET /@admin -> %{http_code}\n' http://localhost:8147/@admin

实测回显:

localhost | localhost | 0.22.3+git-5a6c8e2
livez -> 200
readyz -> 200
nodeinfo/2.0 -> 200
GET /@admin -> 200

/livez、/readyz 是给负载均衡与监控探针用的存活/就绪探针;/nodeinfo/2.0 返回实例软件与统计的标准化描述;/@<用户名> 是用户的公开 Web 主页。完整可调用的接口矩阵见官方 Swagger(/api/swagger),接口面与 Mastodon 客户端 API 对齐。

七、注意事项

  • token 权限即应用申请的 scope:0.19.0 起 GoToSocial 支持带 scope 的授权令牌,申请 read 的 token 无法执行写操作;更早版本令牌是全权限的,给第三方应用授权时先确认版本。
  • CLI 与服务并发:SQLite WAL 下 CLI 子命令可在服务运行中执行,但大批量维护(vacuum、大导出)建议低峰执行。
  • 限流:默认 300 次/5 分钟(advanced-rate-limit-requests),批量脚本调 API 时注意节流,被限流会收到带 Retry-After 的响应。
  • host 即身份:API 返回的 url/uri 全部基于 host 配置,本地测试用 localhost 的实例对外不可联邦,正式实例务必定型正式域名(原因见《GoToSocial 0.22.3 配置参数详解》 5.2)。
  • 配置排障:任何「改了没生效」先用 debug config 看合并后的最终值(见《GoToSocial 0.22.3 配置参数详解》第三章)。

八、常见问题(FAQ)

Q1:admin account create panic 报 password 强度不足? A:CLI 与 Web 用同一套密码强度策略,弱口令(实测 q1w2e3r4 报 password is only 68% strength)直接拒绝;换含大小写+数字+符号的口令。

Q2:/oauth/authorize 返回 500,key redirect_uri not found in session? A:授权流程必须从带 client_id 参数的授权页入口开始(6.2 第 1 步),先初始化会话再登录;直接拿已登录会话访问授权页会因会话缺授权参数而 500。

Q3:media 上传报 422? A:几乎都是文件本身问题(损坏/伪造扩展名/超过 media-local-max-size),看服务端日志定位;上传成功但 meta 为空时检查 Content-Type 是否与文件一致。

Q4:database ping 失败? A:确认 --config-path 指向正确配置(连的库与服务的库一致);SQLite 场景确认 db-address 路径存在且 gotosocial 用户可写;PostgreSQL 场景核对 db-address/port/user/password 与网络可达性。

Q5:如何临时停一个用户的登录而不删数据? A:admin account disable --username <name>;恢复用 admin account enable。彻底停用(suspended)与降权(demote)同族命令见 5.1。

九、参考链接