FreeBSD
此内容尚不支持你的语言。
The relay runs on FreeBSD 14 or newer. This page describes a hardened layout: the relay in a jail as an unprivileged user, pf forwarding public port 443 to it, and TLS terminated by the relay itself.
What the relay does on FreeBSD by itself: at startup it sets RLIMIT_CORE to 0 and disables tracing with procctl(PROC_TRACE_CTL), so it never writes a core file and another process of the same user cannot attach to it. It does not use Capsicum or MAC policies; isolation comes from the jail, the rchat user and the resource limits.
Install
Section titled “Install”Inside the jail, as root, install.sh installs the release binary, the rchat user (home /var/db/rchat), /var/db/rchat (0700), /var/log/rchat (0750), /usr/local/etc/rchat and the rc script:
pkg install -y curl # not in the base system; install.sh keeps redirects on https with itcurl -fsSL https://assets.r-chat.net/install.sh | shTo build from source instead, see Install (pkg install -y rust cmake provides the toolchain), then create the user and directories yourself:
pw useradd rchat -d /var/db/rchat -s /usr/sbin/nologin -c "rChat relay" -w noinstall -o root -g wheel -m 0755 target/release/rchat-server /usr/local/bin/install -d -o rchat -g rchat -m 0700 /var/db/rchatinstall -d -o rchat -g rchat -m 0750 /var/log/rchatinstall -d -o root -g rchat -m 0750 /usr/local/etc/rchatConfiguration
Section titled “Configuration”/usr/local/etc/rchat/server.toml:
[server]bind_addr = "127.0.1.1:8443"websocket_path = "/CHANGE-ME-to-a-long-random-path"relay_identity_path = "/var/db/rchat/relay_identity.key"# Clients dial public 443 (pf rdr), not 8443: tells --print-invite.public_port = 443
# pf forwards public :443 to this listener without terminating TLS,# so built-in ACME (TLS-ALPN-01) works.[server.acme]enabled = truedomains = ["chat.example.com"]cache_dir = "/var/db/rchat/acme"
# Optional: keep held messages across restarts, encrypted, with the key on# the tmpfs that the rc.d script mounts. Leave persist = false for memory only.[server.offline_queue]ttl_secs = 259200persist = truepersist_path = "/var/db/rchat/queue.rcq"persist_key_path = "/var/run/rchat/queue.key"The relay logs a reminder that Let’s Encrypt validates on public port 443; that is expected when pf forwards 443 to another port.
Relay identity
Section titled “Relay identity”Create it once, as the service user, before the first start:
su -m rchat -c '/usr/local/bin/rchat-server --config /usr/local/etc/rchat/server.toml --init-relay-identity'# prints: rk:1:… (version 0), the pin to give your usersSee Relay identity for publishing and rotating it.
To invite people, print the relay invite (a link and a QR code with the address and the pin) as the service user:
su -m rchat -c '/usr/local/bin/rchat-server --config /usr/local/etc/rchat/server.toml --print-invite'In the jail layout the relay binds 8443 but clients dial 443 through pf, so set public_port = 443 under [server] (or pass --public-port 443); otherwise the invite would carry :8443. The host comes from [server.decoy] host, else the first [server.acme] domain. See Inviting people to your relay.
rc.d script
Section titled “rc.d script”Each release publishes the rc script that runs on a FreeBSD 15.1 relay as rchat.rc; install.sh installs it as /usr/local/etc/rc.d/rchat (the file name must match name="rchat"). Its contents:
#!/bin/sh# PROVIDE: rchat# REQUIRE: NETWORKING# KEYWORD: shutdown
. /etc/rc.subr
name="rchat"rcvar="rchat_enable"
load_rc_config $name
: ${rchat_enable:="NO"}: ${rchat_runas:="rchat"} # not rchat_user: rc.subr would run daemon itself as that user: ${rchat_config:="/usr/local/etc/rchat/server.toml"}: ${rchat_log:="/var/log/rchat/server.log"}: ${rchat_log_level:="warn"}
# daemon(8) supervises the relay: -r restarts it 5 s after it exits (an# OOM kill included), -H reopens the log on SIGHUP for newsyslog. daemon# runs as root, writes its pidfile (-P, the supervisor) in root-owned# /var/run, then starts the relay as rchat_runas.pidfile="/var/run/${name}.pid"procname="/usr/sbin/daemon"command="/usr/sbin/daemon"command_args="-r -R 5 -H -o ${rchat_log} -P ${pidfile} -t rchat -u ${rchat_runas} /usr/local/bin/rchat-server --config ${rchat_config} --log-level ${rchat_log_level}"
run_rc_command "$1"fetch -o rchat.rc https://assets.r-chat.net/1.1.0/rchat.rc # only if install.sh did not install itinstall -o root -g wheel -m 0555 rchat.rc /usr/local/etc/rc.d/rchatsysrc rchat_enable=YESservice rchat startWhy it looks like this:
- The variable is
rchat_runas, notrchat_user. rc.subr treats${name}_userspecially and runs the whole command, daemon(8) included, as that user. daemon(8) then cannot-u(“failed to set user environment”) and cannot write its pidfile in root-owned/var/run(“ppidfile … Permission denied”). Withrchat_runas, daemon(8) starts as root, writes the pidfile, and then starts the relay as the service user. The pidfile stays in root-owned/var/run, never in a directory the service user owns. -r -R 5makes daemon(8) supervise the relay and restart it 5 seconds after it exits (an OOM kill included).-Pis the supervisor’s pid, whichservice rchat stopsignals.-H -o /var/log/rchat/server.logwrites a log file that daemon(8) reopens on SIGHUP, so newsyslog can rotate it.
For the jail layout with persist = true, add a start_precmd that creates the tmpfs queue key before each start (use ${rchat_runas} for the owner, and keep the pidfile out of /var/run/rchat):
start_precmd="${name}_prestart"rchat_prestart(){ rchat_gid=$(id -g ${rchat_runas}) install -d -o ${rchat_runas} -g ${rchat_gid} -m 0700 /var/run/rchat if ! mount -p | awk '{print $2}' | grep -qx /var/run/rchat; then mount -t tmpfs -o mode=0700,uid=$(id -u ${rchat_runas}),gid=${rchat_gid} tmpfs /var/run/rchat fi if [ ! -f /var/run/rchat/queue.key ]; then (umask 077; dd if=/dev/random of=/var/run/rchat/queue.key bs=32 count=1 2>/dev/null) chown ${rchat_runas}:${rchat_gid} /var/run/rchat/queue.key chmod 0400 /var/run/rchat/queue.key fi}The queue data lives on ZFS (/var/db) and the key on the tmpfs: different directories and filesystems, as the relay requires. Setting allow_persistent_key = true (for example to keep the key on a GELI-encrypted disk) skips the memory-filesystem check; such a relay can no longer say that its queue key is lost on reboot.
Dedicated VM (no jail)
Section titled “Dedicated VM (no jail)”On a dedicated VM the relay can run directly on the host and listen on :443 itself, with no jail and no pf rdr. mac_portacl(4) lets exactly one uid, the rchat user, bind TCP 443. Each release publishes provision.sh, a script (run as root) that sets this up. Read it before you run it: it replaces /etc/sysctl.conf.local and sets net.inet.ip.portrange.reservedlow and reservedhigh to 0, so that only the mac_portacl rule grants port 443. It creates:
- the
rchatuser (no login shell, home/var/db/rchat) and the directories/usr/local/etc/rchat,/var/db/rchat(0700) and/var/log/rchat(0750); mac_portacl_load="YES"in/boot/loader.confandsecurity.mac.portacl.rules=uid:<rchat uid>:tcp:443in/etc/sysctl.conf.local, with the hardening sysctls (kern.coredump=0,security.bsd.see_other_uids=0, and so on);- a newsyslog entry that rotates
/var/log/rchat/server.logdaily and keeps 14; - sendmail switched off, and
/tmpcleared at boot.
fetch https://assets.r-chat.net/1.1.0/provision.sh https://assets.r-chat.net/1.1.0/server-2gb.tomlsh provision.shpkg install -y curlcurl -fsSL https://assets.r-chat.net/install.sh | sh # binary and rc scriptinstall -o root -g rchat -m 0640 server-2gb.toml /usr/local/etc/rchat/server.toml# edit: domains, and websocket_path (a long random secret)su -m rchat -c '/usr/local/bin/rchat-server --config /usr/local/etc/rchat/server.toml --init-relay-identity'sysrc rchat_enable=YESservice rchat startserver-2gb.toml is a config for a 2 GB host: it binds 0.0.0.0:443, uses built-in ACME ([server.acme]) and sizes the connection and buffer budgets for that much RAM. Its websocket_path is the placeholder /CHANGE-ME-to-a-long-random-path; the relay refuses to start until you replace it.
Gotchas:
- With
security.bsd.see_other_uids=0,psandsockstatshow the relay only undersudo. An empty non-rootsockstat -ldoes not mean the relay is down; checksudo service rchat statusandsudo sockstat -4 -l -p 443. - Let’s Encrypt staging first: start with
staging = trueunder[server.acme]and confirm a certificate is issued. Then stop the relay, move the staging cache aside (mv /var/db/rchat/acme /var/db/rchat/acme.staging), setstaging = falseand start again, so the staging account and certificate are not reused.
pf (jail layout)
Section titled “pf (jail layout)”Forward public TCP 443 to the jail with a plain rdr. This is a TCP forward, so TLS still terminates at the relay:
ext_if = "vtnet0"rchat_jail = "127.0.1.1"
rdr on $ext_if proto tcp from any to any port 443 -> $rchat_jail port 8443pass in quick on $ext_if proto tcp from any to any port 443 flags S/SA keep staterdr keeps the client’s source address, so the relay’s per-address caps and per-source fair shares work as in a direct deployment. Do not put anything that terminates TLS in front of the relay: the protocol binds key authentication to the relay’s own TLS session.