ยฏ\_(ใ)_/ยฏ Building My Rust Blog Platform: A Developer's Journey ๐
Building My Rust Blog Platform: A Developer's Journey ๐
Greetings, fellow Rustaceans, and curious devs! ๐ I recently built and deployed a blog platform using Rust and wanted to share my experience. This isn't your typical WordPress setup - It's a from-scratch Rust application with some pretty cool features.
๐ค Why Rust for a Blog?
I chose Rust for this project because I wanted something performant and secure, and I just enjoy coding in Rust. The ecosystem has matured enough that web development is actually pleasant now (a sentence I couldn't have written a few years ago!).
๐ ๏ธ The Tech Stack
Here's what powers this blog:
- Rust (2021 edition) as the language โค๏ธ
- Axum (v0.8.x) for the web framework ๐
- SQLx (v0.7.x) with SQLite for database operations ๐พ
- Tera (v1.x) for HTML templating ๐
- Tokio for the async runtime โก
โจ Cool Features That Make This Blog Special
I wanted to go beyond basic CRUD operations, so I built in some features that make the blog more enjoyable:
- Tezos Wallet Authentication ๐ - I'm using decentralized auth via Tezos wallet signatures for admin login, which is pretty neat if you're into Web3
- Markdown & HTML Sanitization ๐งน - Write in Markdown but don't worry about XSS attacks
- Enhanced Code Blocks ๐ป - Syntax highlighting plus a one-click "Copy Code" button
- Interactive SVG ๐จโ๐ป - Drop in
[ HACKER_SVG ]
in your post to get an animated, matrix-style graphic - Dark/Light Mode ๐ - Complete with OS preference detection and local storage saving
- USER-Aware View Counting ๐ - So refreshing the page doesn't inflate your numbers
The dynamic theming was particularly fun to implement. It detects your OS preference and remembers your manual local storage selection.
โ๏ธ Axum: The Web Framework Backbone
Axum (v0.8.x) is the core web framework for this blog, orchestrating how requests are handled and responses are generated. Its ergonomic design and tight integration with the Tokio ecosystem made it a natural choice.
Key ways Axum is utilized in this project:
- ย Routing: Defining clear routes for different parts of the blog, such as displaying individual posts, listing all posts, handling admin functionalities (like the Tezos wallet authentication), and serving static assets.
- ย State Management: Axum's state management capabilities are used to share application-wide resources like the SQLx database connection pool and application configuration with route handlers.
- ย Request Handling: Processing incoming HTTP requests, extracting parameters (like post slugs or query parameters), and validating inputs.
- ย Response Generation: Working in tandem with Tera to render HTML templates or return JSON responses for specific API-like endpoints (e.g., for user-aware view counting).
- ย Middleware: Leveraging Axum's middleware system for tasks such as logging, error handling, and managing the session state crucial for features like Tezos wallet authentication.
The framework's focus on type safety and composability helped build a robust and maintainable web application layer.
๐จ Templating with Tera
For rendering HTML, I opted for Tera, a powerful templating engine inspired by Jinja2 and Django templates. This made it easy to create dynamic web pages.
Setting it up with Axum was quite straightforward. I defined a base template with common elements like the header, footer, and navigation, and then child templates for specific pages would extend this base. Tera's syntax is intuitive, allowing for loops, conditionals, and template inheritance, which keeps the front-end code clean and maintainable.
For example, displaying a list of blog posts might look something like this in a Tera template:
{% for post in posts %}
ย <article>
ย ย <h2>{{ post.title }}</h2>
ย ย <p>{{ post.summary }}</p>
ย </article>
{% endfor %}
This approach effectively separated the presentation logic from the application's core Rust code.
๐ข Deploying to Fly.io: Easier Than Expected
Getting this running on Fly.io was surprisingly straightforward. I needed to create a few key files:
- A
Dockerfile
that builds the Rust app ๐ณ - A proper
.dockerignore
to keep build context small ๐๏ธ - The
fly.toml
config file โ๏ธ
The trickiest part was handling the SQLite database. Since Fly.io instances can restart anywhere, I needed to set up a persistent volume:
fly volumes create personal_blog_data --size 1
Then in my fly.toml
, I configured the mount:
[[mounts]]
source = "personal_blog_data"
destination = "/app/data"
And made sure my DATABASE_URL
points to that location:
DATABASE_URL=sqlite:/app/data/rust_blog_app.db
๐งโโ๏ธ The SQLx Offline Mode Lifesaver
One thing that tripped me up initially was SQLx's compile-time query checking. In Docker builds you don't have a database connection during compile time! The solution was to use offline mode:
- Locally run:
cargo sqlx prepare
โจ - Commit the generated
sqlx-data.json
file ๐ - Set
SQLX_OFFLINE=true
in the Dockerfile ๐๏ธ
This lets SQLx validate queries without an actual DB connection during builds.
๐ Setting Up Admin Access
Since I'm using Tezos wallet authentication, I needed to configure my admin wallet:
fly secrets set ADMIN_TEZOS_ADDRESSES=my_tezos_wallet_address
fly secrets set SESSION_SECRET_KEY=a_very_long_random_string
Let me know if you're curious about the implementation details or want to check out the code! I'm happy to share more about specific components.
~ The GitHub link will be posted soon!
๐ Conclusion
Building a blog in Rust was definitely more work than setting up a WordPress site, but the performance, security, and satisfaction of crafting something from scratch made it worthwhile. Plus, now I can tell people that my blog runs on Rust and watch their impressed nods (or confused stares, depending on the crowd). ๐