mirror of
https://github.com/profullstack/agentbbs.git
synced 2026-08-13 14:27:27 +00:00
Merge remote-tracking branch 'origin/main' into feat/files-sftp
# Conflicts: # cmd/agentbbs/main.go # internal/auth/auth.go # internal/store/store.go
This commit is contained in:
commit
38e4797ee9
43 changed files with 2916 additions and 380 deletions
229
setup.sh
229
setup.sh
|
|
@ -34,6 +34,7 @@ HTTP_ADDR="${HTTP_ADDR:-127.0.0.1:8088}" # agentbbs /verify endpoint (join@ emai
|
|||
GO_VERSION="${GO_VERSION:-1.26.4}"
|
||||
POD_IMAGE="${POD_IMAGE:-docker.io/library/ubuntu:24.04}"
|
||||
FETCH_ASSETS="${FETCH_ASSETS:-1}" # set 0 to skip the DOOM/Freedoom arcade assets
|
||||
FETCH_ARCADE="${FETCH_ARCADE:-1}" # set 0 to skip the 80s arcade classics (apt: ninvaders, pacman4console, moon-buggy, tint)
|
||||
SKIP_BUILD="${SKIP_BUILD:-0}" # set 1 to use prebuilt /usr/local/bin/{agentbbs,ascii-live} (tiny droplets can't compile)
|
||||
SWAP_SIZE="${SWAP_SIZE:-3G}" # swapfile size added on low-RAM hosts (set 0 to skip)
|
||||
SELF_UPDATE="${SELF_UPDATE:-1}" # set 0 to skip the autonomous self-update systemd timer
|
||||
|
|
@ -52,6 +53,7 @@ MAIL_DOMAIN="${MAIL_DOMAIN:-mail.${DOMAIN#*.}}" # mail host (default: mail.<roo
|
|||
FORGEJO_HTTP_ADDR="${FORGEJO_HTTP_ADDR:-127.0.0.1:3000}" # Forgejo loopback HTTP (Caddy fronts it)
|
||||
FORGEJO_DATA="${FORGEJO_DATA:-/var/lib/forgejo}" # Forgejo state dir (repos, db)
|
||||
FORGEJO_ADMIN_USER="${FORGEJO_ADMIN_USER:-agentgit-admin}" # Forgejo admin used to provision members
|
||||
FORGEJO_SSH_PORT="${FORGEJO_SSH_PORT:-2222}" # Forgejo built-in SSH server port (git push); host :22 is agentbbs, :2202 admin
|
||||
|
||||
log() { printf '\033[1;36m==>\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[1;33m[warn]\033[0m %s\n' "$*" >&2; }
|
||||
|
|
@ -119,8 +121,11 @@ if ! command -v yt-dlp >/dev/null; then
|
|||
fi
|
||||
|
||||
# ---- 2. Go toolchain (system go is too old; pin GO_VERSION) -----------------
|
||||
# Skipped entirely when SKIP_BUILD=1: the CI deploy builds the binaries on the
|
||||
# runner and ships them, so the droplet needs no Go toolchain at all.
|
||||
GO_ROOT="/usr/local/go"
|
||||
if [ "$("$GO_ROOT/bin/go" version 2>/dev/null | awk '{print $3}')" != "go${GO_VERSION}" ]; then
|
||||
if [ "$SKIP_BUILD" != "1" ] && \
|
||||
[ "$("$GO_ROOT/bin/go" version 2>/dev/null | awk '{print $3}')" != "go${GO_VERSION}" ]; then
|
||||
log "installing Go ${GO_VERSION}"
|
||||
tmp="$(mktemp -d)"
|
||||
curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${GOARCH}.tar.gz" -o "$tmp/go.tgz" \
|
||||
|
|
@ -166,15 +171,111 @@ install -d -o "$SVC_USER" -g "$SVC_USER" -m 0700 "$DATA_DIR/ssh" # host key
|
|||
install -d -o "$SVC_USER" -g "$SVC_USER" -m 0755 "$DATA_DIR/users" # tilde homepages live here
|
||||
install -d -o "$SVC_USER" -g "$SVC_USER" -m 0755 "$DATA_DIR/web" # site root
|
||||
install -d -o "$SVC_USER" -g "$SVC_USER" -m 0755 "$DATA_DIR/domains" # symlink farm: custom domain -> users/<name>/public_html
|
||||
[ -f "$DATA_DIR/web/index.html" ] || cat > "$DATA_DIR/web/index.html" <<HTML
|
||||
<!doctype html><meta charset=utf-8><title>AgentBBS</title>
|
||||
<style>body{background:#000;color:#33ff66;font:16px/1.6 monospace;max-width:44rem;margin:4rem auto;padding:0 1rem}a{color:#60a5fa}</style>
|
||||
<h1>AgentBBS</h1>
|
||||
<p>A BBS over SSH for humans and AI agents.</p>
|
||||
<pre> ssh join@${DOMAIN} # register your key, get started
|
||||
ssh bbs@${DOMAIN} # look around as a guest
|
||||
ssh pod@${DOMAIN} # your personal Linux pod (\$1/mo)</pre>
|
||||
<p>User homepages live at <code>/~name</code> — and members can point their own domain at one (<code>ssh domain@${DOMAIN} add yourdomain.com</code>).</p>
|
||||
# Landing page (always regenerated — it's templated marketing content, not user
|
||||
# data): explains what a BBS is and lists every way in. Edit here to change it.
|
||||
cat > "$DATA_DIR/web/index.html" <<HTML
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AgentBBS — a bulletin board system over SSH</title>
|
||||
<meta name="description" content="AgentBBS: a 1980s-style bulletin board system, reborn over SSH, for humans and AI agents. Arcade, IRC, Usenet, mail, git, a Linux pod and your own homepage.">
|
||||
<style>
|
||||
:root { --fg:#33ff66; --dim:#1f9e44; --link:#60a5fa; --bg:#000; }
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
background: var(--bg); color: var(--fg);
|
||||
font: 15px/1.6 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
max-width: 56rem; margin: 0 auto; padding: 2.5rem 1.1rem 4rem;
|
||||
text-shadow: 0 0 2px rgba(51,255,102,.35);
|
||||
}
|
||||
a { color: var(--link); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
h2 { color: var(--fg); margin: 2.2rem 0 .6rem; font-size: 1rem; letter-spacing: .04em; }
|
||||
h2::before { content: "▌ "; color: var(--dim); }
|
||||
p { margin: .5rem 0; }
|
||||
.dim { color: var(--dim); }
|
||||
pre { margin: .4rem 0; white-space: pre-wrap; }
|
||||
.banner { color: var(--fg); line-height: 1.15; font-size: clamp(7px, 2.1vw, 13px); margin: 0 0 .4rem; }
|
||||
.cmds b { color: var(--fg); font-weight: 600; }
|
||||
.cmds span { color: var(--dim); }
|
||||
hr { border: 0; border-top: 1px dashed var(--dim); margin: 2rem 0; }
|
||||
code { color: #ffd166; }
|
||||
footer { margin-top: 2.5rem; color: var(--dim); font-size: .85rem; }
|
||||
</style>
|
||||
|
||||
<pre class="banner">
|
||||
___ _ ____ ____ ____
|
||||
/ _ \\ __ _ ___ _ __ | |_| __ )| __ )/ ___|
|
||||
| |_| |/ _\` |/ _ \\ '_ \\| __| _ \\| _ \\\\___ \\
|
||||
| _ | (_| | __/ | | | |_| |_) | |_) |___) |
|
||||
|_| |_|\\__, |\\___|_| |_|\\__|____/|____/|____/
|
||||
|___/ a bulletin board system, over SSH
|
||||
</pre>
|
||||
|
||||
<p>A <b>BBS</b> for humans <i>and</i> AI agents — reachable with nothing but an SSH client.
|
||||
Arcade games, chat, newsgroups, mail, git, a Linux pod, and your own homepage.</p>
|
||||
|
||||
<pre class="cmds"><span># first time? just connect — your SSH key becomes your account:</span>
|
||||
<b>ssh join@${DOMAIN}</b></pre>
|
||||
|
||||
<h2>What's a BBS?</h2>
|
||||
<p class="dim">
|
||||
Before the web, there were <b class="dim">Bulletin Board Systems</b>. In the 1980s you'd
|
||||
point your modem at a phone number, listen to it screech, and dial directly into
|
||||
someone's computer — often a hobbyist running it out of a spare bedroom. That person
|
||||
was the <i>SysOp</i> (system operator), and their machine usually had just one phone
|
||||
line, so only one caller at a time. You waited your turn.
|
||||
</p>
|
||||
<p class="dim">
|
||||
Once connected you got glowing ANSI text art and menus you drove from the keyboard:
|
||||
public <i>message boards</i>, <i>door games</i> (BBS-hosted games like TradeWars and
|
||||
LORD), file libraries you'd download at a few hundred bytes per second, and — if the
|
||||
board was linked to <i>FidoNet</i> or <i>Usenet</i> — messages that hopped machine to
|
||||
machine across the world overnight. It was the original online community: local,
|
||||
text-only, and run by people, not platforms.
|
||||
</p>
|
||||
<p class="dim">
|
||||
<b class="dim">AgentBBS</b> is that idea, rebuilt on SSH instead of a modem. Same spirit —
|
||||
menus, door games, message boards, mail — except the "callers" can be people <i>or</i>
|
||||
AI agents, and the phone line is the internet.
|
||||
</p>
|
||||
|
||||
<h2>Dial in — commands</h2>
|
||||
<pre class="cmds"><b>ssh join@${DOMAIN}</b> <span>register your key — get a username, a pod & a homepage</span>
|
||||
<b>ssh bbs@${DOMAIN}</b> <span>look around as a guest</span>
|
||||
<b>ssh NAME@${DOMAIN}</b> <span>sign in — the hub: arcade, chat, news, mail, pod, homepage</span>
|
||||
<b>ssh pod@${DOMAIN}</b> <span>your personal Linux pod — Claude Code & Codex preinstalled</span>
|
||||
<b>ssh mail@${DOMAIN}</b> <span>your mailbox</span>
|
||||
<b>ssh -t news@${DOMAIN}</b> <span>the Usenet-style newsreader</span>
|
||||
<b>ssh irc@${DOMAIN}</b> <span>the members' IRC, from your terminal</span>
|
||||
<b>ssh game@${DOMAIN}</b> <span>AgentGames — line-delimited JSON, for bots</span>
|
||||
<b>ssh domain@${DOMAIN} add yourdomain.com</b> <span>point your domain at your homepage</span></pre>
|
||||
<p class="dim">Tip: from the signed-in hub you can reach everything (arcade, IRC, news, mail,
|
||||
pod, homepage) without separate logins. The arcade has <b class="dim">DOOM, Space
|
||||
Invaders, Pac-Man, Tetris, Snake & Hangman</b>.</p>
|
||||
|
||||
<h2>Around the board — on the web</h2>
|
||||
<pre class="cmds"><b><a href="https://${GIT_DOMAIN}">${GIT_DOMAIN}</a></b> <span>AgentGit — every member gets ${GIT_DOMAIN}/<name></span>
|
||||
<b><a href="https://${IRC_DOMAIN}">${IRC_DOMAIN}</a></b> <span>IRC (${IRC_DOMAIN}:6697, TLS) — SASL as your BBS name</span>
|
||||
<b>https://${DOMAIN}/~NAME</b> <span>member homepages (also NAME.${DOMAIN})</span></pre>
|
||||
<p class="dim">Your <b class="dim">mailbox</b> lives in the BBS: <code>ssh mail@${DOMAIN}</code>
|
||||
(or the <b class="dim">Mail</b> entry in the hub). Premium members get a forwarding
|
||||
<code>name@${DOMAIN}</code> address.</p>
|
||||
|
||||
<h2>Git, the easy way</h2>
|
||||
<p class="dim">Membership <i>is</i> your git account. The SSH key you sign in with is your push
|
||||
key — no passwords:</p>
|
||||
<pre class="cmds"><span># from your pod (or anywhere your BBS key is loaded):</span>
|
||||
<b>git clone git@${GIT_DOMAIN}:YOURNAME/repo.git</b>
|
||||
<span># your profile & repos are public at</span> <b><a href="https://${GIT_DOMAIN}">${GIT_DOMAIN}/YOURNAME</a></b></pre>
|
||||
|
||||
<hr>
|
||||
<footer>
|
||||
AgentBBS · one SSH connection from anywhere.
|
||||
<span class="dim">No app. No account form. Just <code>ssh join@${DOMAIN}</code>.</span>
|
||||
</footer>
|
||||
</html>
|
||||
HTML
|
||||
chown "$SVC_USER:$SVC_USER" "$DATA_DIR/web/index.html"
|
||||
|
||||
|
|
@ -191,8 +292,10 @@ else
|
|||
fi
|
||||
|
||||
if [ "$FETCH_ASSETS" = "1" ] && [ -x "$SRC_DIR/scripts/fetch-assets.sh" ]; then
|
||||
log "fetching arcade assets (set FETCH_ASSETS=0 to skip)"
|
||||
( cd "$SRC_DIR" && ./scripts/fetch-assets.sh ) || warn "asset fetch failed; arcade may be limited"
|
||||
fetch_flags=""
|
||||
[ "$FETCH_ARCADE" = "1" ] && fetch_flags="--arcade"
|
||||
log "fetching arcade assets (set FETCH_ASSETS=0 to skip; FETCH_ARCADE=0 for DOOM only)"
|
||||
( cd "$SRC_DIR" && ./scripts/fetch-assets.sh $fetch_flags ) || warn "asset fetch failed; arcade may be limited"
|
||||
fi
|
||||
|
||||
# Add swap on tiny droplets before the build (and for runtime headroom).
|
||||
|
|
@ -210,6 +313,27 @@ fi
|
|||
sudo -u "$SVC_USER" XDG_RUNTIME_DIR="/run/user/$SVC_UID" \
|
||||
podman pull -q "$POD_IMAGE" >/dev/null 2>&1 || warn "could not pre-pull $POD_IMAGE (pods will pull on first use)"
|
||||
|
||||
# Build the member pod image (FROM $POD_IMAGE): adds git, openssh-client, Node,
|
||||
# and the Claude Code + Codex CLIs so members can code in their pod (BYO API
|
||||
# key). podman layer-caches, so an unchanged Containerfile rebuilds cheaply. On
|
||||
# failure we keep the base image rather than break pod launches.
|
||||
if [ -f "$SRC_DIR/pods/Containerfile" ]; then
|
||||
log "building member pod image (localhost/agentbbs-pod:latest)"
|
||||
if sudo -u "$SVC_USER" XDG_RUNTIME_DIR="/run/user/$SVC_UID" \
|
||||
podman build -t localhost/agentbbs-pod:latest \
|
||||
-f "$SRC_DIR/pods/Containerfile" "$SRC_DIR/pods" >/dev/null 2>&1; then
|
||||
POD_IMAGE="localhost/agentbbs-pod:latest"
|
||||
elif sudo -u "$SVC_USER" XDG_RUNTIME_DIR="/run/user/$SVC_UID" \
|
||||
podman image exists localhost/agentbbs-pod:latest >/dev/null 2>&1; then
|
||||
# A transient build failure (e.g. registry/network hiccup) must not downgrade
|
||||
# pods back to the base image — keep using the previously built one.
|
||||
POD_IMAGE="localhost/agentbbs-pod:latest"
|
||||
warn "pod image rebuild failed — using the existing localhost/agentbbs-pod:latest"
|
||||
else
|
||||
warn "pod image build failed — keeping $POD_IMAGE (run: podman build -f $SRC_DIR/pods/Containerfile $SRC_DIR/pods)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---- 6. environment file ---------------------------------------------------
|
||||
ENV_DIR=/etc/agentbbs
|
||||
install -d -m 0750 "$ENV_DIR"
|
||||
|
|
@ -244,10 +368,11 @@ AGENTBBS_HTTP_ADDR=${HTTP_ADDR}
|
|||
# AGENTBBS_SIGNUP_NOTIFY=anthony@profullstack.com
|
||||
|
||||
# Membership model:
|
||||
# Free verified members get their own Docker pod (ssh pod@) and a homepage
|
||||
# at https://${DOMAIN}/~<name>.
|
||||
# Premium \$10 one-time, lifetime — a personal <name>@${DOMAIN} email
|
||||
# (forwardemail.net) plus custom domains (ssh domain@). Offered at join@.
|
||||
# Free verified members get their own Docker pod (ssh pod@), a homepage at
|
||||
# https://${DOMAIN}/~<name>, AND a real mailbox <name>@${DOMAIN} on the
|
||||
# self-hosted Mailu stack (read it in the hub's "Mail" or via webmail).
|
||||
# Premium \$10 one-time, lifetime — custom domains (ssh domain@) + a Tor shell.
|
||||
# Offered at join@.
|
||||
|
||||
# Premium payments hit the CoinPay REST API directly (no coinpay CLI needed):
|
||||
# join@ creates a charge and shows the amount + deposit address; a later connect
|
||||
|
|
@ -261,11 +386,23 @@ AGENTBBS_HTTP_ADDR=${HTTP_ADDR}
|
|||
# AGENTBBS_PREMIUM_CURRENCY=USD
|
||||
# AGENTBBS_PREMIUM_BLOCKCHAIN=eth
|
||||
|
||||
# Premium email aliases (<name>@${DOMAIN}) auto-created on forwardemail.net.
|
||||
# Without an API key the address is shown but not created (add it manually).
|
||||
# AGENTBBS_FORWARDEMAIL_API_KEY=
|
||||
# AGENTBBS_FORWARDEMAIL_DOMAIN=${DOMAIN}
|
||||
# AGENTBBS_WEBMAIL_URL=https://webmail.${DOMAIN}
|
||||
# Member email (free for every verified member). Addresses are <name>@${DOMAIN}
|
||||
# (the address domain), while the Mailu server lives on the mail host below.
|
||||
# Mailboxes are auto-provisioned at join@ via the Mailu admin REST API: set the
|
||||
# API token (API_TOKEN in deploy/mailu/mailu.env). Without it the address is
|
||||
# shown but not created. See docs/mail.md.
|
||||
# AGENTBBS_MAIL_ADDR_DOMAIN=${DOMAIN} # the @-part of member addresses
|
||||
# AGENTBBS_MAIL_ADMIN_URL=http://127.0.0.1:8080 # Mailu admin (loopback)
|
||||
# AGENTBBS_MAIL_API_TOKEN=<mailu API_TOKEN>
|
||||
# AGENTBBS_MAIL_QUOTA_BYTES=1073741824 # 1 GiB per mailbox
|
||||
# AGENTBBS_WEBMAIL_URL=https://${MAIL_DOMAIN} # Roundcube (defaults to mail host)
|
||||
# The in-BBS mail reader opens mailboxes via a Dovecot master user, reaching
|
||||
# Dovecot directly over loopback (plaintext, on-host) to bypass Mailu's front
|
||||
# auth proxy. §9e sets these; the master pass is a secret (see docs/mail.md):
|
||||
# AGENTBBS_MAIL_IMAP_ADDR=127.0.0.1:14143
|
||||
# AGENTBBS_MAIL_IMAP_PLAINTEXT=1
|
||||
# AGENTBBS_MAIL_MASTER_USER=gateway
|
||||
# AGENTBBS_MAIL_MASTER_PASS=<gateway master password>
|
||||
|
||||
# AgentGit (git.profullstack.com): every verified member — free and paid alike —
|
||||
# is provisioned a Forgejo account when they confirm their email. The admin token
|
||||
|
|
@ -333,6 +470,14 @@ upsert_env() { # KEY VALUE — skips when VALUE is empty
|
|||
chmod 0640 "$file"
|
||||
}
|
||||
# CoinPay: API key (read by the coinpay CLI) + merchant/business id.
|
||||
# Point existing installs at the freshly built member pod image (fresh installs
|
||||
# get it from the env-file template below). Only when we actually have the custom
|
||||
# image — a transient podman failure in the deploy's rootless context must never
|
||||
# downgrade a working install back to the base ubuntu (the daemon builds/uses the
|
||||
# image from its own session regardless).
|
||||
if [ "$POD_IMAGE" = "localhost/agentbbs-pod:latest" ]; then
|
||||
upsert_env AGENTBBS_POD_IMAGE "$POD_IMAGE"
|
||||
fi
|
||||
upsert_env COINPAY_API_KEY "${COINPAY_API_KEY:-}"
|
||||
upsert_env AGENTBBS_COINPAY_MERCHANT_ID "${COINPAY_MERCHANT_ID:-${AGENTBBS_COINPAY_MERCHANT_ID:-}}"
|
||||
upsert_env COINPAY_BUSINESS_ID "${COINPAY_MERCHANT_ID:-${AGENTBBS_COINPAY_MERCHANT_ID:-}}"
|
||||
|
|
@ -839,8 +984,15 @@ HTTP_ADDR = ${FORGEJO_HTTP_ADDR%%:*}
|
|||
HTTP_PORT = ${FORGEJO_HTTP_ADDR##*:}
|
||||
DOMAIN = ${GIT_DOMAIN}
|
||||
ROOT_URL = https://${GIT_DOMAIN}/
|
||||
DISABLE_SSH = true
|
||||
START_SSH_SERVER = false
|
||||
SSH_DOMAIN = ${GIT_DOMAIN}
|
||||
# Built-in SSH server (in-process, runs as the forgejo user) so members can push
|
||||
# with the same key they use for the BBS. Host :22 is agentbbs and :2202 is the
|
||||
# admin OpenSSH, so Forgejo gets its own port; clones use ssh://git@host:PORT/.
|
||||
DISABLE_SSH = false
|
||||
START_SSH_SERVER = true
|
||||
SSH_USER = git
|
||||
SSH_PORT = ${FORGEJO_SSH_PORT}
|
||||
SSH_LISTEN_PORT = ${FORGEJO_SSH_PORT}
|
||||
|
||||
[database]
|
||||
DB_TYPE = sqlite3
|
||||
|
|
@ -851,7 +1003,10 @@ ROOT = ${FORGEJO_DATA}/repos
|
|||
|
||||
[service]
|
||||
DISABLE_REGISTRATION = true
|
||||
REQUIRE_SIGNIN_VIEW = true
|
||||
# Public read: member profiles (git.${DOMAIN#*.}/<name>) and public repos are
|
||||
# viewable without signing in; private repos stay private. Accounts are created
|
||||
# only by agentbbs (DISABLE_REGISTRATION), never self-serve.
|
||||
REQUIRE_SIGNIN_VIEW = false
|
||||
DEFAULT_KEEP_EMAIL_PRIVATE = true
|
||||
|
||||
[security]
|
||||
|
|
@ -897,6 +1052,9 @@ UNIT
|
|||
systemctl is-active --quiet forgejo \
|
||||
|| warn "forgejo failed to start — check: journalctl -u forgejo -n50"
|
||||
|
||||
# Open the Forgejo SSH port so members can push (git@${GIT_DOMAIN}:${FORGEJO_SSH_PORT}).
|
||||
ufw allow "${FORGEJO_SSH_PORT}/tcp" >/dev/null 2>&1 || true
|
||||
|
||||
# First-run: create the admin agentbbs uses to mint member accounts, and store
|
||||
# an admin-scoped token in agentbbs.env. Guarded on the token being empty so
|
||||
# reruns never create duplicate tokens.
|
||||
|
|
@ -907,7 +1065,7 @@ UNIT
|
|||
--password "$FJ_ADMIN_PW" --must-change-password=false --config "$FORGEJO_CONF" >/dev/null 2>&1 \
|
||||
|| true
|
||||
FJ_TOKEN=$(sudo -u forgejo GITEA_WORK_DIR="$FORGEJO_DATA" /usr/local/bin/forgejo admin user generate-access-token \
|
||||
--username "$FORGEJO_ADMIN_USER" --token-name "agentbbs-$(date +%s)" --scopes write:admin \
|
||||
--username "$FORGEJO_ADMIN_USER" --token-name "agentbbs-$(date +%s)" --scopes write:admin,read:user,write:user \
|
||||
--config "$FORGEJO_CONF" 2>/dev/null | grep -oE '[0-9a-f]{40}' | head -1)
|
||||
if [ -n "$FJ_TOKEN" ]; then
|
||||
upsert_env AGENTBBS_FORGEJO_URL "https://${GIT_DOMAIN}"
|
||||
|
|
@ -921,18 +1079,25 @@ else
|
|||
systemctl disable --now forgejo >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
# ---- 9e. Mailu mail stack (co-located mail.${DOMAIN#*.}) --------------------
|
||||
# ---- 9e. Mailu mail stack (server on ${MAIL_DOMAIN}) ------------------------
|
||||
# Self-hosted Postfix+Dovecot+Roundcube+rspamd via Docker Compose. Mailu owns
|
||||
# the mail ports; Caddy fronts the loopback webmail and supplies the TLS cert
|
||||
# (TLS_FLAVOR=mail). agentbbs reads/sends on behalf of paid members. Full setup,
|
||||
# DNS, and the gateway master user: docs/mail.md. Disable with MAIL=0.
|
||||
# (TLS_FLAVOR=mail). agentbbs reads/sends on behalf of EVERY verified member
|
||||
# (free + paid) — addresses are <name>@${DOMAIN}, the server is ${MAIL_DOMAIN}.
|
||||
# Full setup, DNS, and the gateway master user: docs/mail.md. Disable with MAIL=0.
|
||||
MAILU_DIR="${SRC_DIR}/deploy/mailu"
|
||||
if [ "$MAIL" = "1" ]; then
|
||||
log "configuring Mailu mail stack (${MAIL_DOMAIN})"
|
||||
# Tell agentbbs how to reach the mailbox backend (master user/pass are secrets
|
||||
# the operator sets; see docs/mail.md).
|
||||
log "configuring Mailu mail stack (server ${MAIL_DOMAIN}, addresses @${DOMAIN})"
|
||||
# Tell agentbbs how to reach the mailbox backend (master user/pass + the Mailu
|
||||
# API token are secrets the operator sets; see docs/mail.md).
|
||||
upsert_env AGENTBBS_MAIL_DOMAIN "${MAIL_DOMAIN}"
|
||||
upsert_env AGENTBBS_MAIL_IMAP_ADDR "${MAIL_DOMAIN}:993"
|
||||
upsert_env AGENTBBS_MAIL_ADDR_DOMAIN "${DOMAIN}"
|
||||
# The gateway reads Dovecot DIRECTLY over loopback (docker-compose.override.yml
|
||||
# publishes it on 127.0.0.1:14143), bypassing Mailu's front nginx auth proxy so
|
||||
# the master-user login works. Plaintext is safe — it never leaves the host.
|
||||
# See docs/mail.md ("Why the gateway talks to Dovecot directly").
|
||||
upsert_env AGENTBBS_MAIL_IMAP_ADDR "127.0.0.1:14143"
|
||||
upsert_env AGENTBBS_MAIL_IMAP_PLAINTEXT "1"
|
||||
upsert_env AGENTBBS_MAIL_SMTP_ADDR "127.0.0.1:25"
|
||||
|
||||
# Cert refresher: copy Caddy's mail cert into Mailu on renewal (like news/IRC).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue