Skip to content

Latest commit

 

History

History
764 lines (543 loc) · 26.2 KB

SETUP.md

File metadata and controls

764 lines (543 loc) · 26.2 KB

RustChan Setup Guide

Current setup and deployment guide for Linux, macOS, and Windows.

Current version: 1.7.1.

This guide reflects the current RustChan architecture:

  • Tor onion hosting is built in via Arti. You do not install or manage a separate tor service.
  • Images, GIF/WebP animation, HEIC/HEIF, container metadata, common audio waveforms, and supported PDF previews run internally in Rust. Unsupported PDF previews use the built-in SVG placeholder.
  • ffmpeg is optional, but recommended for video thumbnails, WebM transcoding, and uncovered audio codecs. Standalone ffprobe and external PDF renderers are not required.
  • The post edit form and self-delete flow share a 60-second self-action window after posting.

Contents

  1. What RustChan Needs
  2. Quick Start
  3. Install Rust
  4. Install ffmpeg
  5. Verify WebP and WebM Support
  6. Build and Run
  7. First-Run Files and Layout
  8. Important settings.toml Options
  9. Tor Onion Service
  10. HTTPS and TLS
  11. Linux Service Setup
  12. Reverse Proxy Notes
  13. Admin Bootstrapping
  14. Banner Artwork Requirements
  15. Updating
  16. Troubleshooting

What RustChan Needs

RustChan is a single Rust binary. A basic install only needs:

  • Rust 1.99 or newer to build it
  • a writable runtime data directory (next to the binary by default, or selected with --data-dir)
  • ffmpeg for video processing and uncovered audio codecs

RustChan does not require:

  • Docker
  • Postgres or MySQL
  • Redis
  • a separate Tor daemon

Quick Start

git clone https://github.com/csd113/RustChan.git
cd RustChan
cargo build --release
./target/release/rustchan-cli

On first launch RustChan creates rustchan-data/settings.toml, rustchan-data/logs/, and the rest of its runtime directories next to the binary.

Then in another terminal:

./target/release/rustchan-cli admin create-admin admin "ChangeThisPasswordNow"
./target/release/rustchan-cli admin create-board b "Random" "General discussion"

Open:

  • http://localhost:8080
  • admin panel: http://localhost:8080/admin

If TLS is enabled in settings.toml, RustChan also serves HTTPS on port 8443 by default.

Install Rust

Linux and macOS

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
rustc --version
cargo --version

Windows

Install Rust with rustup-init.exe from rustup.rs, then open a new PowerShell window and verify:

rustc --version
cargo --version

Install ffmpeg

ffmpeg is optional, but RustChan is significantly better with it.

When ffmpeg is available, RustChan can:

  • extract video thumbnails
  • generate waveform thumbnails for uncovered audio codecs (for example AC-3 or Speex)
  • transcode MP4 uploads to WebM when VP9 and Opus are available

Without ffmpeg, images, animation, metadata inspection, supported PDF previews, and common audio waveforms still work. Video processing and uncovered-codec waveform previews use their existing placeholders.

Debian / Ubuntu / Raspberry Pi OS

sudo apt update
sudo apt install -y ffmpeg

Fedora

sudo dnf install -y ffmpeg

If your base Fedora repos do not provide the codec-enabled build you want, use RPM Fusion.

macOS

brew install ffmpeg

Windows

winget install --id Gyan.FFmpeg -e

Then make sure the FFmpeg bin directory is on PATH.

Verify ffmpeg Exists

ffmpeg -version

If you want RustChan to refuse startup when ffmpeg is missing, set:

require_ffmpeg = true

Verify WebP and WebM Support

WebP images, GIF → animated WebP, and animated WebP validation are built into RustChan through Rust crates and remain available without FFmpeg. Video thumbnails use FFmpeg to extract a PNG frame and Rust to encode WebP.

For video/WebM conversion, RustChan checks the installed decoder, encoder and muxer lists independently:

  • libvpx-vp9 for WebM video encoding
  • libopus for WebM audio encoding
  • the webm muxer for output
  • AV1 decoders for AV1 inputs (AV1 encoder availability is reported separately; output remains VP9 + Opus)

Use these commands:

ffmpeg -encoders | rg libvpx-vp9
ffmpeg -encoders | rg libopus
ffmpeg -muxers | rg webm
ffmpeg -decoders | rg av1

If you do not have rg, use:

ffmpeg -encoders | grep libvpx-vp9
ffmpeg -encoders | grep libopus

WebM conversion needs both selected encoders and the WebM muxer. AV1 input also needs an AV1 decoder; an AV1 encoder is optional and is not selected for RustChan output.

What Each Encoder Enables

  • libvpx-vp9 + libopus: MP4/Matroska and WebM/AV1 to VP9/Opus WebM conversion. Compatible VP8/VP9 WebM with Opus/Vorbis audio is preserved.

Linux Notes

On Debian-family systems, the usual install is:

sudo apt update
sudo apt install -y ffmpeg libvpx-dev libopus-dev

The important part is still the actual ffmpeg -encoders output. Package names alone do not guarantee your installed FFmpeg binary was built with every encoder enabled.

macOS Notes

Most Homebrew FFmpeg installs are fine, but verify with:

ffmpeg -encoders | rg 'libvpx-vp9|libopus'

If one is missing, reinstall FFmpeg from a build source that includes that codec set.

Windows Notes

Use a full FFmpeg build rather than a minimal one, then verify with:

ffmpeg -encoders | Select-String libvpx-vp9
ffmpeg -encoders | Select-String libopus

What RustChan Does If Support Is Missing

RustChan will log warnings and continue:

  • missing VP9, Opus or the WebM muxer: video uploads retain their originals
  • missing an AV1 decoder: AV1 conversion fails with a useful diagnostic and retains the original
  • missing FFmpeg: Rust-native still and animated WebP continue to work

These warnings appear in the console at startup and in rustchan-data/logs/.

Build and Run

Build

cargo build --release

Binary:

  • Linux/macOS: target/release/rustchan-cli
  • Windows: target/release/rustchan-cli.exe

Run

./target/release/rustchan-cli

Optional CLI Flags

./target/release/rustchan-cli --port 9090
./target/release/rustchan-cli --data-dir /absolute/path/to/rustchan-data

First-Run Files and Layout

By default RustChan stores runtime state in rustchan-data/ next to the binary. Pass --data-dir with an absolute, non-root path to place the complete runtime layout elsewhere. This is the supported layout for service installations; it includes settings.toml, the database, uploads, logs, backups, and runtime secrets. The selected data directory has this layout:

rustchan-data/
├── settings.toml
├── chan.db
├── logs/
│   └── rustchan.YYYY-MM-DD.log
├── backups/
│   ├── full/
│   └── boards/
├── runtime/
│   ├── tls/
│   ├── tor/
│   │   ├── state/
│   │   └── cache/
│   ├── favicon/
│   └── tmp/
└── boards/

## Banner Artwork Requirements

RustChan `1.4.0` includes board banners plus a separate home-page announcement banner.

Banner upload requirements:

- exact `468x60` aspect ratio
- minimum size `468x60`
- recommended size `936x120`
- input can be PNG, JPEG, or WebP
- RustChan converts uploaded banner images to WebP automatically

Board banner placement:

- board index: under the board name/description, above `[Index] [Catalog] [Archive]`
- catalog: under the board name/description, above `Sort By:` and `Show OP Comment:`
- no banner on thread pages
- no banner on archive pages
- no banner on search pages

Home page banner placement:

- separate centered banner box on the home page
- intended for MOTD/news/announcement use

Banner link behavior:

- internal board and internal-path links work directly
- external links can be enabled in the admin panel
- when enabled, external banner clicks go through an on-site warning page before redirecting

Important notes:

  • settings.toml is generated automatically on first run
  • cookie_secret is generated automatically on first run
  • Tor state and onion keys live under rustchan-data/runtime/tor/state/
  • logs rotate daily under rustchan-data/logs/

Important settings.toml Options

The generated file documents every setting inline. Commonly tuned settings:

forum_name = "RustChan"
site_subtitle = "select board to proceed"
default_theme = "forest"
enabled_builtin_themes = ["forest", "blue-sky", "deep-orbit", "terminal", "dorfic", "chanclassic", "aero", "neoncubicle", "fluorogrid"]
port = 8080

max_image_size_mb = 8
max_video_size_mb = 50
max_audio_size_mb = 150

enable_tor_support = true
# tor_only = false
# tor_bootstrap_timeout_secs = 120
# tor_max_concurrent_streams = 512
# tor_service_nickname = "rustchan"

require_ffmpeg = false
# ffmpeg_path = "/usr/local/bin/ffmpeg"
ffmpeg_timeout_secs = 600

[tls]
enabled = false
require_https = false
port = 8443
# redirect_http = true
# http_port = 8080

A Few High-Impact Settings

  • enable_tor_support = true: built-in onion service is on
  • tor_only = true: bind RustChan to loopback and serve only through Tor
  • require_ffmpeg = true: fail startup if ffmpeg is missing
  • [tls].enabled = true: explicitly enable RustChan's native HTTPS listener
  • [tls].require_https = true: opt into disabling public plaintext application access
  • ffmpeg_timeout_secs = 600: max runtime for a single ffmpeg job

Tor Onion Service

RustChan includes built-in Tor onion service hosting through Arti.

You do not need to:

  • install tor
  • write a torrc
  • manage a hidden service directory manually

Default Behavior

On current builds, the generated settings.toml enables Tor support by default:

enable_tor_support = true

On first startup with Tor enabled, RustChan:

  1. creates the Tor runtime directories
  2. bootstraps to the Tor network
  3. generates or loads the onion service keypair
  4. starts serving the site over .onion

The first bootstrap usually takes longer than later boots because Tor directory data has to be downloaded and cached.

Where the Onion Key Lives

Back up:

rustchan-data/runtime/tor/state/

That directory contains the persistent onion identity. If you lose it, the next startup will generate a new onion address.

Tor-Only Mode

If you want RustChan reachable only through Tor:

enable_tor_support = true
tor_only = true

In this mode RustChan binds to loopback instead of 0.0.0.0, so clearnet access is blocked.

Tor Permissions

RustChan creates the Tor state directory with restricted permissions on Unix. If you move the data directory manually, preserve write access for the RustChan service user.

HTTPS and TLS

RustChan has built-in HTTPS support.

The generated settings.toml currently includes:

[tls]
enabled = false
port = 8443

This means:

  • HTTP is available on the main app port
  • HTTPS support is configured but disabled until you turn it on
  • when enabled, RustChan can generate a local self-signed development certificate

Observability Endpoints

/healthz is public and intentionally minimal. /readyz returns only a readiness status by default, and /metrics returns 404 unless explicitly enabled.

Only enable detailed readiness or metrics for a trusted scrape path:

public_readiness_details = true
public_metrics_enabled = true

Detailed readiness and metrics include operational state such as database schema health, backup freshness, media backlog, maintenance state, and Tor readiness. If you expose them, use a reverse-proxy allowlist, private network, or equivalent network boundary. Tor-facing deployments should keep the defaults unless you intentionally monitor those endpoints externally.

Default Settings

# Setting Scope Default Enabled by default? Admin? Config? Notes
3 Homepage board-card new-thread badges site-wide true true Yes Yes First boot seeds DB from settings.toml; later admin-owned.
4 Board/catalog thread-card new-reply badges site-wide true true Yes Yes First boot seeds DB from settings.toml; later admin-owned.
9 Allow external banner links after warning page banner false false Yes No DB-backed admin setting only.
12 Board NSFW flag per-board false false Yes No New-board create form leaves this unchecked.
16 Archive overflow threads per-board true true Yes No Global prune config can still override hard-delete behavior.
20 CAPTCHA on threads and replies per-board false false Yes No Per-board admin toggle.
24 Allow images per-board true true Yes No New boards start with image uploads enabled.
25 Allow video per-board true true Yes No New boards start with video uploads enabled.
26 Allow audio per-board false false Yes No New-board create form leaves this unchecked.
27 Allow PDF uploads per-board false false Yes No Per-board admin toggle.
28 Allow any file uploads per-board false false Yes No Only available when the global arbitrary-file gate is enabled.
29 Allow tripcodes per-board true true Yes No Per-board admin toggle.
30 Embed video links (YouTube) per-board true true Yes No New-board default for fresh and existing installs.
31 Show thread-local poster IDs per-board true true Yes No New-board default for fresh and existing installs.
32 Collapse long greentext per-board false false Yes No Per-board render behavior toggle.
33 Allow users to edit their own posts during the 60-second grace window per-board true true Yes No New-board default for fresh and existing installs.
34 Allow users to delete their own posts during the 60-second grace window per-board true true Yes No New-board default for fresh and existing installs.
38 Master arbitrary-file upload gate media false false Indirect Yes When off, boards cannot enable generic file uploads.
39 Require ffmpeg at startup media false false No Yes When off, RustChan degrades gracefully where possible.
46 TLS enabled TLS false false No Yes Generated settings.toml keeps native HTTPS off until explicitly enabled.
48 Redirect HTTP to HTTPS TLS false false No Yes Only relevant when native TLS is enabled.
50 ACME enabled TLS false false No Yes The ACME section stays commented out by default.
51 ACME staging TLS true true No Yes Applies if the ACME section is enabled and the field is omitted.
53 Built-in Tor support Tor true true No Yes Generated config enables Tor support by default.
54 Tor-only mode Tor false false No Yes Keeps clearnet access on unless you explicitly disable it.
55 Public detailed readiness observability false false No Yes Keep off unless /readyz is behind a trusted scrape path.
56 Public metrics observability false false No Yes Keep off unless /metrics is behind a trusted scrape path.
60 Include Tor hidden-service keys in automatic full backups backup / Tor true true Yes Yes Admin saves rewrite settings.toml; existing installs keep their current configured value until changed.
66 Archive before prune maintenance / archive true true No Yes Global override: prune archives instead of hard-deletes.
75 New banner enabled flag banner true true Yes No Applies to newly uploaded global, board, and home banners.
76 New global/board banner shows on board index banner true true Yes No Home banners do not use this placement flag.
77 New global/board banner shows on catalog banner true true Yes No Home banners do not use this placement flag.

Common Modes

Local or LAN Testing

Keep built-in TLS enabled and use the self-signed certificate.

Public Production Reverse Proxy

Many operators still prefer putting nginx or Caddy in front and terminating TLS there.

ACME / Let's Encrypt

RustChan also supports ACME-based certificates when built with the tls-acme feature and configured in [tls.acme].

Linux Service Setup

Run RustChan as a dedicated unprivileged user.

1. Create a Service User

sudo useradd --system --home /var/lib/rustchan --create-home --shell /usr/sbin/nologin rustchan

2. Build and Install the Binary

cargo build --release
sudo install -o root -g root -m 0755 target/release/rustchan-cli /usr/local/bin/rustchan-cli
sudo mkdir -p /var/lib/rustchan
sudo chown -R rustchan:rustchan /var/lib/rustchan

3. First Start as the Service User

This creates settings.toml and the runtime layout:

sudo -u rustchan -H /usr/local/bin/rustchan-cli --data-dir /var/lib/rustchan

Stop it after the first start, edit /var/lib/rustchan/settings.toml, then continue.

4. Create a systemd Unit

Create /etc/systemd/system/rustchan.service:

[Unit]
Description=RustChan
After=network-online.target
Wants=network-online.target

[Service]
User=rustchan
Group=rustchan
WorkingDirectory=/var/lib/rustchan
StateDirectory=rustchan
StateDirectoryMode=0700
ExecStart=/usr/local/bin/rustchan-cli --data-dir /var/lib/rustchan serve
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true

[Install]
WantedBy=multi-user.target

StateDirectory=rustchan asks systemd to keep /var/lib/rustchan writable by the unprivileged service account. The explicit --data-dir keeps all runtime state there even though the root-owned executable lives under /usr/local/bin.

Then:

sudo systemctl daemon-reload
sudo systemctl enable --now rustchan
sudo journalctl -u rustchan -f

5. Optional Environment Overrides

You can add overrides with:

sudo systemctl edit rustchan

Example:

[Service]
Environment=CHAN_BIND=127.0.0.1:8080
Environment=CHAN_REQUIRE_FFMPEG=true

Reverse Proxy Notes

If you put nginx or Caddy in front of RustChan:

  • point the proxy at the RustChan HTTP listener
  • set CHAN_BEHIND_PROXY=true if you want proxy headers trusted
  • set CHAN_TRUSTED_PROXY_CIDRS to the proxy's loopback or private CIDR when the proxy is not on localhost
  • decide whether TLS terminates at the proxy or inside RustChan

When RustChan's built-in TLS is enabled, HTTPS is an additional listener and the main HTTP application listener remains available by default. Set require_https = true under [tls] to opt into HTTPS-only access. Independently, redirect_http = true exposes tls.http_port as a redirect listener instead of serving application routes there. With the built-in Tor service enabled, HTTPS-only mode also keeps a loopback HTTP backend that accepts only connections registered by its in-process Tor proxy.

RustChan accepts bounded Content-Length request bodies and rejects Transfer-Encoding at the application boundary. Configure a reverse proxy to dechunk request bodies before forwarding them. Request headers are limited to 32 KiB per value and 64 KiB in aggregate.

Typical loopback setup:

internet -> nginx/caddy -> 127.0.0.1:8080 -> RustChan

If you use a reverse proxy and terminate TLS there, make sure your proxy forwards the usual headers and that RustChan is not accidentally exposed directly on the public interface.

Admin Bootstrapping

Create the first admin account:

./target/release/rustchan-cli admin create-admin admin "UseAStrongPassword"

Create a board:

./target/release/rustchan-cli admin create-board tech "Technology" "Programming and hardware"

Other useful commands:

./target/release/rustchan-cli admin list-admins
./target/release/rustchan-cli admin list-boards
./target/release/rustchan-cli admin reset-password admin "NewStrongPassword"

Updating

git pull
cargo build --release
sudo install -o root -g root -m 0755 target/release/rustchan-cli /usr/local/bin/rustchan-cli
sudo systemctl restart rustchan

Before major updates, back up:

  • rustchan-data/chan.db
  • rustchan-data/boards/
  • rustchan-data/runtime/tor/state/
  • rustchan-data/settings.toml

Or use the built-in backup tools from the admin panel.

RustChan 1.5.0 retains the database structure introduced in 1.4.1. Fresh installs create the current baseline directly. Existing structurally valid 1.4.1 databases are verified and stamped as schema version 1.5.0; recognized older schema shapes use the existing compatibility repairs. Partial, unknown, or corrupt schemas are rejected without deleting data. Historical chan_net_* tables remain for database and backup compatibility, but ChanNet itself and the --chan-net option have been removed. Remove that option from service commands before upgrading. Obsolete ChanNet settings can remain in settings.toml and are ignored. Back up your data before upgrading. Future structural schema changes should add forward migrations tied to RustChan release versions.

Troubleshooting

The TUI shows ffmpeg warnings

Run:

ffmpeg -version
ffmpeg -encoders | rg 'libvpx-vp9|libopus'

If one of those encoders is missing, RustChan will still run but some media features will be downgraded.

Tor never becomes ready

Check:

  • outbound network connectivity
  • whether the RustChan service user can write to rustchan-data/runtime/tor/
  • whether tor_bootstrap_timeout_secs needs to be raised

Also review:

rustchan-data/logs/rustchan.YYYY-MM-DD.log

HTTPS fails on startup

Check:

  • whether [tls] enabled = true is intentional
  • whether the configured HTTPS port is available
  • whether your ACME or manual cert settings are correct if you use those modes

The service starts but uploads fail

Make sure the RustChan user can write to:

  • rustchan-data/
  • the uploads directory
  • rustchan-data/runtime/

The onion address changed unexpectedly

That usually means the Tor state directory was deleted, replaced, or not persisted:

rustchan-data/runtime/tor/state/

Back that directory up if the onion address matters.

Optional administrator-controlled software updates

Eligible native Linux installs use the same rustchan-cli executable for the application and update controller. Start with the existing account and data directory; see Software Updates for ownership requirements, verified backups, source adoption and exceptional reboot recovery. Protected installations and containers use their deployment's upgrade procedure.

Internal media processing

RustChan handles JPEG/PNG/BMP/TIFF, static and animated WebP, GIF conversion, HEIC/HEIF still pictures, container metadata, and common audio waveforms in Rust. PDF previews cover a small bounded vector/text subset; compressed streams, embedded images/fonts and other unbudgeted features use the existing SVG preview while the original PDF remains available.

FFmpeg remains the video backend. It also preserves waveform support for audio variants the internal decoders do not cover, including AC-3, Speex, unsupported AAC profiles and Opus multistream/surround. See the media migration report for format coverage, resource limits and verification.

Applying administrator configuration

Live controls keep applying immediately. Other controls show their active, saved and next-start values. Saving never restarts RustChan; managed Linux and opted-in supervised containers expose Restart RustChan for pending settings. See settings restarts for the complete classification, supervisor setup, graceful shutdown and failure recovery.

Thread archives and retention

Threads leave the active index when background maintenance finds more than the board's Max threads non-sticky active threads. It keeps the newest last-bump and thread-ID pairs; locked threads count, sticky active threads do not. New thread creation durably schedules maintenance, so overflow can be visible briefly. Startup and periodic reconciliation recover outstanding work.

Replies bump until the board's bump limit is reached. Sage replies count toward that limit without bumping. The bump limit stops bumps; it does not immediately archive the thread. There is no time-based thread expiry.

Archive overflow threads controls automatic archival, with the global archive_before_prune safety net (default true) also enabling it. Hard deletion of active overflow occurs only when both are off. Existing archives and their navigation remain available even when automatic archival is disabled.

Max archived threads is a count cap (1–10,000), not permanent retention. Maintenance keeps the most recently bumped archived threads, breaking ties by ascending thread ID. Archived sticky threads are also subject to the cap; sticky is not an archive preservation setting. Lowering the cap permanently removes overflow threads. Invalid retention values are rejected rather than clamped; omitted retention fields preserve the saved limits.

Archival keeps the same /{board}/thread/{id} URL and media references. Archived threads are read-only, including polls; users can browse their results, quoting, spoilers and attachments. Board search includes archived posts. Board index, catalog and unread history show active threads. Administrators can manually archive or delete a thread using the existing authenticated, CSRF-protected controls. There is no public unarchive/preservation control.

The archive and prune transitions use one SQLite write transaction. Pruned media is removed only when no other database references remain, using durable, restart-replayable file cleanup. Failed filesystem cleanup stays queued and logged. Archive policy is read when maintenance executes, not from stale job payloads. Changing the global TOML/environment safety net requires restart; board settings are live. Monitor background-job failures if maintenance is unable to acquire the database lock or complete cleanup.