`server.https` picked the scheme for every generated link, and it also decides whether cookies are marked Secure. The two are separate questions, and a config that said `publicPort = 443` with `https = false` produced `http://host:443` in every feed `<link>`, `<guid>`, the OpenSearch template and the unfurl metadata. Nothing serves plain HTTP on 443, so no such link was ever usable, and nothing warned about it. Take the scheme from the port when the port is 443 or 80 -- they only mean one thing -- and from `https` otherwise, so `https://host:8443` still works. A default port is never appended. The `https` flag keeps governing cookies, and startup now logs a warning when the port says TLS and the flag does not, since the cookies are then not Secure. The logic moves into a small pure function so the combinations can be tested exhaustively rather than through a loaded config. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
teapot
A privacy-focused Twitter/X frontend written in Rust.
Features
- Privacy-focused: No third-party JavaScript, tracking, ads, or remote fonts
- RSS feeds: Subscribe to any user's tweets
- FxEmbed-style Discord embeds:
- Multiple images displayed in carousel on mobile
- Videos play directly in the embed
- Proper image dimensions for better layout
- ActivityPub JSON endpoint for rich embeds
Requirements
- Rust 1.96.1+
- Twitter/X session tokens for API access
Building
cargo build --release
Configuration
- Copy the example config:
cp config/teapot.example.toml config/teapot.toml
-
Edit
config/teapot.tomlwith your settings. -
Create a sessions file with your Twitter/X credentials:
cp sessions.example.jsonl sessions.jsonl
# Edit sessions.jsonl with your auth_token and ct0 from browser cookies
Cookie sessions use auth_token and ct0. OAuth sessions use
oauth_token and oauth_secret. See sessions.example.jsonl for the JSONL
shape. Never commit a real session or generated teapot.toml.
Running
# Development
cargo run
# Production
./target/release/teapot
The server will start on http://localhost:8080 by default.
Getting Twitter Sessions
To use the Twitter API, you need session tokens from a logged-in Twitter account:
- Log into Twitter/X in your browser
- Open Developer Tools (F12) → Application → Cookies
- Copy the values of
auth_tokenandct0 - Add them to
sessions.jsonl
Project Structure
teapot/
├── src/
│ ├── main.rs # Entry point
│ ├── config.rs # Configuration
│ ├── error.rs # Error types
│ ├── types/ # Data structures (User, Tweet, Timeline, etc.)
│ ├── api/ # Twitter API client, OAuth, parsing
│ ├── cache/ # In-process caching
│ ├── routes/ # HTTP route handlers
│ ├── views/ # Maud HTML templates
│ └── utils/ # Utilities (HMAC, formatters)
├── public/ # Static assets (CSS, JS, fonts)
├── config/ # Configuration files
└── Cargo.toml # Dependencies
Embed Improvements
This rewrite includes FxEmbed-style improvements for Discord embeds:
Multiple Images
Discord can display all images from a tweet in a carousel. This works via an ActivityPub JSON endpoint at /users/{username}/statuses/{id} that returns media attachments.
Video Playback
Videos can be played directly in Discord embeds using twitter:player meta tags:
twitter:player- Embed URLtwitter:player:stream- Direct MP4 URLtwitter:player:width/height- Dimensions
Image Dimensions
All images include og:image:width and og:image:height meta tags for proper layout.