SSD Nodes Learn 8GB 内存 — 每年 $66
指南 Matt Connor作者: Matt Connor · 更新于 2026-08-01

Listmonk VPS自托管部署:Ubuntu 24.04配置指南

在 Ubuntu 24.04 上部署 Listmonk v6.2.0,配置 PostgreSQL、config.toml、systemd 与 TLS,并连接 SMTP。了解它为何不负责发信,以及建立送达信誉通常需要数周。

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, July 30, 2026.

Listmonk 自托管新闻简报所需的组件

Listmonk 是一个自托管的新闻简报和邮件列表管理器:一个 Go 二进制文件、一个 PostgreSQL 数据库、一个配置文件和一个 systemd 单元。小型 VPS 即可轻松运行它,因为 Listmonk 只存储订阅者并对营销活动排队,从不自行发送邮件。它会将每封邮件交给 SMTP(简单邮件传输协议)服务器,因此邮件送达率取决于该服务器的信誉,而不是此软件。

本指南将在 Ubuntu 24.04 上安装 Listmonk v6.2.0,这是截至 2026 年 7 月的当前版本。您需要一台具有公共 IP 地址的 VPS、一个由您控制的域名,以及 PostgreSQL 12 或更高版本。安装大约需要 1 小时。建立发送信誉需要数周,本文将在接近末尾的部分介绍相关内容。

安装 PostgreSQL 并创建数据库

Ubuntu 24.04 自带的软件仓库提供 PostgreSQL 16,版本远高于 Listmonk 的要求。

sudo apt update
sudo apt install -y postgresql curl
sudo systemctl enable --now postgresql

在一个 psql 会话中创建角色和数据库。-v ON_ERROR_STOP=1 会使 psql 在第一个语句失败时退出,因此即使存在拼写错误,也不会留下看似完成但实际不完整的配置。

sudo -u postgres psql -v ON_ERROR_STOP=1 <<'SQL'
CREATE USER listmonk WITH PASSWORD 'pick-a-long-random-password';
CREATE DATABASE listmonk OWNER listmonk;
SQL

OWNER listmonk 不是装饰选项。安装架构时会创建表、类型、索引和函数,因此该角色必须拥有数据库。让 Listmonk 使用其他角色拥有的数据库时,安装会因 permission denied 而停止,即使你已经运行过 GRANT CONNECT

继续操作前,确认数据库已存在。

sudo -u postgres psql -tAc "SELECT datname FROM pg_database WHERE datname='listmonk';"

该命令会输出 listmonk。如果输出为空行,说明 CREATE 语句从未执行,请重新查看 psql 的输出。

安装 Listmonk 二进制文件

Listmonk 为每种架构发布一个静态二进制文件。先检查您的架构,因为在 ARM VPS 上使用 amd64 二进制文件时,内核会拒绝执行该文件。

dpkg --print-architecture
cd /tmp
curl -fsSLO https://github.com/knadh/listmonk/releases/download/v6.2.0/listmonk_6.2.0_linux_amd64.tar.gz
tar -xzf listmonk_6.2.0_linux_amd64.tar.gz
sudo install -m 755 listmonk /usr/bin/listmonk
listmonk --version

如果使用 ARM VPS,请将文件名中的 amd64 替换为 arm64listmonk --version 能打印版本字符串,首先证明该二进制文件与机器匹配。

生成 config.toml 并限制其权限

--new-config 会将 config.toml 写入当前工作目录。因此,cd 位于 sh -c 内,而不是位于 sudo 之前。

sudo install -d -m 750 /etc/listmonk
sudo sh -c 'cd /etc/listmonk && listmonk --new-config'

生成的文件很短。在 [app] 下,address = "localhost:9000" 仅将 HTTP 服务器绑定到回环地址。因此,在其前面配置反向代理之前,管理面板无法从互联网访问。不要修改这一行。在 [db] 下,你会看到 host = "localhost"port = 5432user = "listmonk"database = "listmonk"ssl_mode = "disable"。这些默认值已经与创建的数据库匹配,因此只需修改密码这一行。

当 Postgres 在同一台主机上监听回环地址时,ssl_mode = "disable" 配置正确,因为该流量不会离开本机。如果将数据库移到另一台主机,请将其设置为 require,否则密码会以明文形式通过网络传输。

编辑 [db] 下的密码行,使其与该角色匹配,然后创建服务账户,并禁止其他登录账户访问该文件。

sudo useradd --system --home-dir /var/lib/listmonk --create-home --shell /usr/sbin/nologin listmonk
sudo chown -R root:listmonk /etc/listmonk
sudo chmod 640 /etc/listmonk/config.toml

现在,服务账户可以读取该文件,其他账户都无法读取。

sudo -u listmonk cat /etc/listmonk/config.toml > /dev/null && echo readable
stat -c '%U:%G %a' /etc/listmonk/config.toml

第一个命令会输出 readable。第二个命令会输出 root:listmonk 640。任何其他非特权账户尝试执行相同的 cat 时,都会得到 Permission denied。这正是目的所在:该文件以明文保存数据库密码,而服务器通常有多个登录账户。相同原则适用于运行的每项服务,因此请阅读一次最小权限服务用户,并在所有服务中应用这一原则。

使用 --install 创建架构

--install 会创建表并写入默认设置。使用环境变量设置第一个管理员登录信息,以便在管理面板可访问之前,账户就已经存在。

sudo -u listmonk env LISTMONK_ADMIN_USER=admin \
  LISTMONK_ADMIN_PASSWORD='another-long-random-password' \
  listmonk --config /etc/listmonk/config.toml --install --yes

--yes 会回答确认提示。在自动化之前先阅读一次该提示,因为 --install 是首次安装命令,并且会删除现有的 Listmonk 架构。在生产数据库上再次运行它会删除订阅者。对于可能运行两次的脚本,请使用 --install --idempotent --yes;如果表已存在,该命令不会执行任何操作。新版本中发布的架构变更应使用 --upgrade 应用,不能使用 --install

请从数据库端检查结果,不要通过浏览器检查。

sudo -u postgres psql -d listmonk -c '\dt'
sudo -u postgres psql -d listmonk -tAc "SELECT username FROM users;"

第一条命令会列出 Listmonk 表,其中包括 subscriberslistscampaignstemplatesbounces。第二条命令会输出 admin。如果第二条命令返回空结果,说明环境变量从未传递给该进程,因此管理面板会要求您在浏览器中创建第一个用户。

在 systemd 下运行 Listmonk

编写 /etc/systemd/system/listmonk.service

[Unit]
Description=Listmonk newsletter and mailing list manager
After=network-online.target postgresql.service
Wants=network-online.target

[Service]
Type=simple
User=listmonk
Group=listmonk
WorkingDirectory=/var/lib/listmonk
ExecStart=/usr/bin/listmonk --config /etc/listmonk/config.toml
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true

[Install]
WantedBy=multi-user.target

WorkingDirectory 很重要,因为 Listmonk 会以它为基准解析相对路径,包括文件系统媒体上传路径。After=postgresql.service 只负责安排启动顺序,不会等待 Postgres 接受连接,因此 Restart=on-failure 可以处理 Listmonk 启动过早、无法连接的情况。

sudo systemctl daemon-reload
sudo systemctl enable --now listmonk
ss -ltnp | grep 9000
curl -sI http://127.0.0.1:9000/

ss 应显示 127.0.0.1:9000 处于 LISTEN 状态。curl 返回任何 HTTP 状态行都表示服务器正在响应。curlConnection refused 失败表示进程在启动期间退出,journalctl -u listmonk -n 50 --no-pager 会说明原因。请注意,enable --now 才能在重启后继续生效:手动启动的进程会在下一次内核升级后消失。

在前端部署 nginx 和 TLS

Listmonk 在回环接口上使用纯 HTTP,因此由 nginx 终止 TLS(传输层安全协议)并转发请求。

server {
    listen 443 ssl;
    server_name lists.example.com;

    client_max_body_size 25m;

    location / {
        proxy_pass http://127.0.0.1:9000;
        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;
    }
}

由于订阅者导入和媒体上传都使用文件 POST 请求,因此必须提高 client_max_body_size 的值。nginx 默认拒绝超过 1 MB 的请求,并返回 413 Request Entity Too Large。使用 certbot 签发证书。certbot 还会为您写入 listen 443 ssl 配置行,并设置从端口 80 重定向的规则:具体步骤请参阅nginx 的 Let's Encrypt 证书指南。开放端口 80 和 443,保持端口 9000 关闭,因为代理通过回环接口访问该端口。如果尚未配置防火墙,请先阅读ufw 防火墙基础

然后打开管理面板,在 Settings 中将根 URL 设置为 https://lists.example.com。全新安装默认使用 http://localhost:9000,Listmonk 会将该值写入邮件中的每个退订链接和媒体 URL。修改前先发送营销活动,收件人收到的链接就会指向各自的计算机。对收件人来说,这些链接无法访问;对垃圾邮件过滤器来说,这表明发件人甚至无法正确配置自己的域名。

连接 SMTP(不在 config.toml 中)

搜索 config.toml,找不到 SMTP 配置段。邮件设置存储在数据库的 settings 表中,您可以在管理面板的“设置”和“SMTP”下编辑这些设置。这就是生成的文件保持简短的原因,也是 SMTP 设置更改无需重启的原因。

SMTP 服务器本身有两个可行选项。自行运行 SMTP 服务器。这样,IP 声誉完全由您负责,这本身也是一个独立项目:使用 Mailcow 运行您自己的邮件服务器介绍了相关内容。或者将 Listmonk 指向事务性邮件中继服务,由其他服务商负责 IP 声誉。

无论选择哪种方式,都应使用带 STARTTLS 的端口 587,或使用隐式 TLS 的端口 465。不要计划使用出站端口 25。大多数 VPS 提供商会在新账户上默认阻止该端口。端口 25 被阻止时,表现与连接挂起完全相同,因为数据包会被丢弃,而不是被拒绝。因此,客户端会等待超时,而不会快速失败。

在信任它之前先进行测试。创建一个列表,将您自己的地址添加为订阅者,然后发送一封仅包含一个收件人的营销邮件。打开收到的邮件并读取完整邮件头。接收端添加的 Authentication-Results 邮件头可以告诉您 SPF 和 DKIM 是否通过。

投递能力就是全部工作

Listmonk 负责构建邮件、跟踪列表并移交邮件。邮件能否到达收件箱,完全由接收服务商根据发送 IP 地址和发送域名决定。新的 VPS IP 没有任何历史记录,而所有大型邮箱服务商都会将没有历史记录视为轻度可疑。

以下四项不可省略:

  • SPF(发件人策略框架)TXT 记录,列出允许代表您的域名发送邮件的主机。
  • DKIM(域密钥识别邮件)密钥,以 TXT 记录发布,并由邮件服务器而不是 Listmonk 完成签名。
  • DMARC(基于域的消息认证、报告和一致性)记录,告知接收方前两项检查失败时应如何处理。
  • Listmonk 会读取的退信邮箱,以便拒收邮件的地址从列表中移除,而不是被无限重试。

然后开始时要缓慢发送。一个从未发送过邮件的域名,如果突然在 1 小时内发送 10000 封邮件,其行为特征与账户被入侵完全一致,因此会被按此类邮件进行过滤。先向活跃度最高的订阅者发送,再用数天时间逐步提高发送量。

每个模板还必须包含有效的退订链接。在 Listmonk 模板中,该链接是 {{ UnsubscribeURL }};活动正文会插入到 {{ template "content" . }} 所在的位置,并且每个模板中必须恰好出现一次。没有退订链接的活动会引发垃圾邮件投诉,而不是退订。投诉是最快损害发送信誉的方式,而建立发送信誉可能需要数周。

备份,以及实际恢复所需的内容

必须将两项内容移出此服务器:数据库转储和 config.toml。如果您将图像上传到营销活动中,还要备份 media 目录。

sudo -u postgres pg_dump -Fc listmonk > listmonk-$(date +%F).dump

该转储包含订阅者、营销活动、模板和所有设置,包括 SMTP 凭据。因此请对其加密,并将其保存在此服务器之外。备份调度已经有成熟方案:请参阅使用 restic 将加密备份存储到远程存储config.toml只有几行内容,但包含数据库密码,因此请按相同方式处理。

升级必须按以下顺序进行。停止服务,创建转储,将 /usr/bin 中的二进制文件替换为新版本,运行 listmonk --config /etc/listmonk/config.toml --upgrade,然后启动服务。架构迁移只能向前执行,因此该转储是唯一的回滚途径。

Listmonk 为什么无法启动?

先使用 journalctl -u listmonk -n 50 --no-pager 读取日志。几乎所有启动失败都会在 [db] 块中显示为一行信息。

pq: password authentication failed for user "listmonk" 表示 [db] 中的密码与 Postgres 角色的密码不匹配。pq 前缀表示 Postgres 驱动报告了服务器拒绝请求,因此配置已正确读取,问题出在凭据上。使用 sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';" 重置该角色,然后将完全相同的字符串写入文件。

pq: database "listmonk" does not exist 表示 [db] 中的 database 值不是实际存在的数据库名称。sudo -u postgres psql -l 会列出服务器上实际存在的数据库,其中包括你误用的名称拼写。

在运行 --install 期间出现 permission denied,表示该角色可以连接,但不是该数据库的所有者,因此无法在其中创建表。使用 sudo -u postgres psql -c "ALTER DATABASE listmonk OWNER TO listmonk;" 修复,然后再次运行安装程序。

服务始终无法启动,日志中指出了配置文件。listmonk 身份运行的进程无法打开权限设置为 root:root、模式为 600 的 config.tomlstat -c '%U:%G %a' /etc/listmonk/config.toml 应输出 root:listmonk 640,其上级目录应为 root:listmonk 750

管理面板可以运行,但没有邮件到达。 这不是启动问题。先检查 Settings 和 SMTP,然后检查管理面板中该 campaign 自身的日志。该日志会记录邮件服务器针对每次尝试返回的错误。

FAQ

使用 Listmonk 是否需要自己的邮件服务器?

不需要。Listmonk 不是邮件服务器。它需要能够接收并投递邮件的服务器的 SMTP 凭据。该服务器可以是事务性中继,也可以是您自行运行的邮件服务器。在管理面板的 Settings 和 SMTP 中设置这些凭据,不要在 config.toml 中设置,因为邮件设置存储在数据库中。使用端口 587 和 STARTTLS,或使用端口 465 和隐式 TLS,因为大多数 VPS 提供商会在新账户上阻止出站端口 25。

为什么我的 campaign 中的链接指向 localhost:9000?

根 URL 设置仍为安装时的默认值 http://localhost:9000。Listmonk 会在发送 campaign 时,将该值写入退订链接和媒体 URL。打开管理面板中的 Settings,将根 URL 设置为实际的 HTTPS 地址,然后保存。已经投递的邮件无法更正,因此请先向自己发送测试 campaign,并在发送给真实列表前点击其中的退订链接。

再次运行 --install 会清除订阅者吗?

会。--install 是首次安装程序,会删除现有的 Listmonk schema;--yes 会移除原本用于警告您的确认提示。对于可能运行两次的脚本,请使用 --install --idempotent --yes。如果表已存在,该命令不会执行任何操作。要在新版本中应用 schema 更改,请停止服务,创建 pg_dump,然后运行 --upgrade

为什么 Listmonk 显示用户 listmonk 的密码身份验证失败?

/etc/listmonk/config.toml[db] 块内的密码与同名 Postgres 角色的密码不匹配。日志行是 pq: password authentication failed for user "listmonk"pq 表示 Postgres 驱动转发了服务器的拒绝信息。这说明配置文件已找到并读取。使用 sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';" 重置该角色的密码,将完全相同的字符串写入配置文件,然后运行 sudo systemctl restart listmonk

#listmonk#newsletter#email#自托管#postgres#systemd