BlahgLegacy#
BlahgLegacy is a fork of Blahg that fixes bugs, adds some new features and has a UI friendlier to older browsers. The bug fixes and Jetstream config are also available as a set of patches for upstream Blahg on the main branch.
BlahgLegacy uses a new lexicon to enable support for these new features.
BlahgLegacy renders blog posts from data on your PDS, which can be fetched live or imported from the command line. It can also ingest references in other AppViews (Bluesky) to display links to them.
Features#
Compared to Blahg, BlahgLegacy has the following features:
-
A default UI that is friendly to older web browsers.
-
Support for setting the Jetstream endpoint instead of being hardcoded to use one of Bluesky's instances.
-
Ability to use Jetstream compression (required zstd dictionary not included)
-
The ability to set the listen address.
-
Support for setting a subtitle in your blog posts
-
Tags to categorize your blog posts. Includes searching posts by tag.
-
A description for embed/social media cards.
-
An automatic RSS feed.
-
Various bug fixes.
Storage & Infrastructure#
BlahgLegacy supports both SQLite and PostgreSQL, although only the former is tested. Similarly, it can use S3-compatible storage or the disk. Like the original Blahg it uses Miijinja for page templates and Comrak to render Markdown to HTML.
Web Interface#
BlahgLegacy's default templates are designed to be accessible with older web browsers. All data is served by BlahgLegacy; it does not make the client call other servers to view blog posts.
The following endpoints are available:
/: Homepage with list of all posts/posts/{slug}: Individual post page/posts/{slug}/{collection}: Post interaction references (likes, reposts, etc)/static/*: Static asset serving (CSS, JS, images)/tag/{tag}: List of all posts with the given tag/sitemap.xml: XML Sitemap/rss.xml: Auto-generated RSS feed
Architecture#
Blahg consists of two main components:
- blahg - The main application that runs the web interface and, if enabled, processes real-time events
- blahg-import - A command-line tool for importing individual posts from AT URIs
Data Flow#
- The recommended way is to listen for events from the Jetstream and auto-import blog posts that are created.
- Alternatively, you can import posts manually with blahg-import.
Dependencies#
This project uses the following atproto crates:
atproto-identity- Identity resolution and verificationatproto-record- Record handling and parsingatproto-client- ATProtocol client functionalityatproto-jetstream- Real-time event streaming
Installation#
Prerequisites#
- Rust 1.87 or higher
- Cargo
- PostgreSQL or SQLite (depending on your database choice)
Building from Source#
git clone https://tangled.org/@engielolz.ritsuko.akizuki.best/blahg
cd blahg
cargo build --release
Feature Flags#
You can exclude features for a faster build:
sqlite: Enable SQLite database support (default: enabled)postgres: Enable PostgreSQL database support (default: enabled)s3: Enable S3-compatible object storage (default: enabled)embed: Embed templates in binary for production (default: disabled)reload: Enable template hot-reloading for development (default: enabled)
To use them, append --no-default-features --features "features,you,want" to the build command.
For example, for a production build with just sqlite and embedded templates: cargo build --release --no-default-features --features "sqlite,embed"
Docker#
docker build -t blahg .
docker run -p 8080:8080 blahg
Usage#
Running the Server#
# Minimal set up. Uses SQLite
touch blahg.db
BLAHG_AUTHOR="did:web:example.com" \
./target/release/blahg
# Configuration with custom database, listen address, storage path and jetstream
touch mycustom.db
BLAHG_AUTHOR="did:plc:example" \
BLAHG_DATABASE_URL="sqlite://mycustom.db" \
BLAHG_HTTP_LISTEN_ADDRESS="127.0.0.1" \
BLAHG_ATTACHMENT_STORAGE="./blobs" \
BLAHG_JETSTREAM_HOSTNAME="jetstream.fire.hose.cam" \
BLAHG_JETSTREAM_DICTIONARY="./zstd_dictionary" \
./target/release/blahg
Importing Posts#
BlahgLegacy will by default automatically import posts that are created by the account defined in BLAHG_AUTHOR. Posts can be imported manually with blahg-import as follows:
# Set your database first
export BLAHG_DATABASE_URL="sqlite://mycustom.db"
# Import a single post
./target/release/blahg-import at://did:plc:example/best.akizuki.blahglegacy.post/abc123
# Import multiple posts
./target/release/blahg-import \
at://did:plc:example/best.akizuki.blahglegacy.post/abc123 \
at://did:plc:example/best.akizuki.blahglegacy.post/def456
Configuration#
Configuration is managed via environment variables:
Core Settings#
BLAHG_AUTHOR: AT Protocol DID (required)BLAHG_EXTERNAL_BASE: Base URL for your blog (default:http://localhost:8080)BLAHG_HTTP_PORT: HTTP server port (default:8080)BLAHG_HTTP_LISTEN_ADDRESS: IP Address to listen on (default:0.0.0.0)BLAHG_HTTP_TEMPLATES_PATH: Path of HTTP templates to use if reload feature is on (default:<project root>/templates)
Database#
BLAHG_DATABASE_URL: Database connection string- SQLite:
sqlite://blahg.db(default) - PostgreSQL:
postgresql://user:pass@localhost/blahg
- SQLite:
Storage#
BLAHG_ATTACHMENT_STORAGE: Content storage location- Filesystem:
./attachments(default) - S3:
s3://bucket/prefix/
- Filesystem:
ATProtocol#
BLAHG_ENABLE_JETSTREAM: Enable real-time event processing (default:true)BLAHG_JETSTREAM_HOSTNAME: Jetstream instance to use (default:jetstream2.us-east.bsky.network)BLAHG_JETSTREAM_DICTIONARY: Path to the Jetstream zstd dictionary. Setting this will enable Jetstream compression (optional)BLAHG_JETSTREAM_CURSOR_PATH: Path to store Jetstream cursor (optional)BLAHG_PLC_HOSTNAME: PLC directory hostname (default:plc.directory)
HTTP Client#
BLAHG_USER_AGENT: HTTP client user agentBLAHG_HTTP_CLIENT_TIMEOUT: HTTP client timeout (default:10s)BLAHG_CERTIFICATE_BUNDLES: Additional CA certificates (comma-separated paths, optional)
Development#
Development Environment#
# Run in development mode with hot-reloading
cargo run
# Run with specific features
cargo run --no-default-features --features "sqlite,reload"
Running Tests#
cargo test
Linting and Type Checking#
cargo clippy
cargo check
Lexicon#
BlahgLegacy uses its own lexicon schema, best.akizuki.blahglegacy.post. A basic idea of what a post looks like:
{
"title": "string", // Post title (max 100 graphemes)
"subtitle": "string", // Post subtitle (max 200 graphemes)
"description": "string", // Post description (max 200 graphemes)
"publishedAt": "datetime", // Publication timestamp
"updatedAt": "datetime", // Last updated timestamp
"tags": ["string"], // Tags (max 10, 30 graphemes each)
"text": "blob", // Post content (markdown, max 1MB)
"attachments": [ // Optional image attachments
{
"content": "blob", // Image blob (max 5MB)
}
]
}
Please consult the lexicon JSON for specifics.
"Removed" features#
The following features are not in the BlahgLegacy lexicon schema. Do note however that neither of these features are actually used by the original Blahg, although it does check for the presence of a langs tag.
langs- You can use tags to categorize posts by language.alt- Supply alt text within the post instead.
Contributing#
Contributions are welcome! Please feel free to submit a Pull Request.
License#
BlahgLegacy is available under the MIT License.