In-browser WebAssembly we trust

Rust compiles to machine code, which runs as an executable file on your computer. You can also compile it to WebAssembly (Wasm for short) and have it run in the browser.

Until recently, if you wanted to add interactivity to a web page, or do a bunch of calculations in-browser, you'd use JavaScript. Now that Wasm is supported in all modern browsers, we can use Rust (or another compatible language) and run much closer to the metal.

Good times! Here's how to do it.

Firstly, install wasm-pack. It's a tool that helps build Rust code for the web.

Then, create a new Rust project with wasm-pack new my-wasm-project. This will generate a basic Rust library for you.

We only need to worry about src/ for now.

mod utils;

use wasm_bindgen::prelude::*;

extern "C" {
    fn alert(s: &str);

pub fn greet() {
    alert("Hello, my-wasm-test!");

The extern "C" block pulls the alert function in from JavaScript and we "export" the greet function using pub so we can call it from JavaScript.

Those #[wasm_bindgen] annotations are what bind our Rust code to JavaScript. They tell the compiler where the Wasm module should interface with JavaScript.

The alert function ... shows an alert box on the page. Cool. Let's do something a bit more interesting!

mod utils;

use wasm_bindgen::prelude::*;

pub fn fibonacci(n: u32) -> u32 {
    match n {
        0 => 0,
        1 => 1,
        _ => fibonacci(n - 1) + fibonacci(n - 2),

This function calculates the nth Fibonacci number. Now we can hook it up and call this function from our page. But first, we need to compile it into WebAssembly.

Build your Wasm module with wasm-pack build --target web in the root of your project. This will create a pkg directory with a wasm.js file and a wasm_bg.wasm file.

We'll need an index.js file at the root of our project to import our Wasm module.

import init, { fibonacci } from "./pkg/my_wasm_project.js";

await init();
let result = fibonacci(32);
console.log(result); // 2178309

And an index.html to load our script.

<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Hello World!</title>
    <script type="module" defer async src="./index.js"></script>
    Hello World!

Now serve your root directory with miniserve (or your favourite local static file server) and open index.html in your browser. You should see the result of the fibonacci function in the console.

The 32nd Fibonacci number is 2178309 btw.

And there you have it. Wasm running in-browser.

'Till next time. ✌️

Running a Mastodon instance entirely free forever

My single-user Mastodon instance has been ticking away at for a while now, over a year at least. All up, I've paid zero dollars to keep it running. I've had a few people ask me to write up something about it, so here it is.

If you're comfortable logging into a Linux server via SSH and running commands you shouldn't have any major troubles setting it up, but it will take a few hours of work. Enjoy!

Firstly though, why would anyone even want to run their own Mastodon instance? Well, for the fun of mucking around with servers and software, perhaps? Maybe for the freedom to post whatever you want on your own platform and no dumb billionaire can suspend you or force you to take it down? Who knows? Anyway...

To run a Mastodon instance you need 2 things.

  1. A domain, or subdomain.
  2. A server, 2GB RAM minimum. 50GB disk space minimum.

Getting a proper domain name for free is more art than science these days, especially since Freenom shut down new registrations. Here are some other places to try.

  1. - They make you jump through a few hoops, plus it can take up to a month or two (or forever) to get approved.
  2. - domain. 1-year registrations only, but you can renew manually for free each year.

(If you know of any other places to get free domains, please let me know.)

You can also use a subdomain. Subdomains are easier to get for free. Try some of these places or do a search online.

  2. GitHub free-subdomain topic

Or else, if you already own a domain name, you can create a subdomain like or or whatever you like.

Now you need a server to point your domain to.

You could use any old computer that you have lying around the house, or you could sign up for the free tier on the Oracle Cloud. This is what I'm using currently.

Google Cloud also offers a free server, but they only give you 30GB storage and 1GB of outbound traffic and Mastodon will chew through this pretty quick. But you could try GoToSocial, Pleroma, or Akkoma instead, which are a bit more lightweight.

(If anyone knows any other free-forever tier VPSs please let me know too.)

I wrote up this little guide a while ago about how to get 2x Oracle Cloud servers free forever. These are x86 servers with 1GB RAM each. 1GB is a bit small for a Mastodon instance, but I can confirm that it does run if you enable some swap space and don't enable Elastic Search. You could even try splitting the database and the web server between the two separate servers, if you're feeling adventurous.

Good news though. Oracle has now added ARM servers to their free tier. These are the Ampere A1 Compute servers. You can create from 1 up to 4 servers with 24GB of RAM spread between them, which is more than enough for a Mastodon instance. And they're free forever too. I am running mine on a 2-thread ARM CPU with 12GB RAM and 50GB block storage.

Oracle gives you up to 200GB of block storage, which you can spread across all your servers. I have had some issues with running low on disk space and having to set up scripts to compress media etc (see below), so I'd probably recommend using 100GB for your Mastodon instance as a minimum. Unfortunately, Mastodon uses a lot of space for storing accounts and media etc. You can hook up object storage later if you want, but it's not necessary for starters.

OK, so now you have your domain and you have it pointed to the IP address of your server (or your home IP address with ports 80 and 443 forwarded to your internal address). Now you need to install Mastodon. Simply follow the instructions over at the official guide to get started. There are quite a few steps involved, but it's not too hard if you take it one step at a time.

If everything went well, you should now have a working Mastodon instance. Log in and start posting!


Here are some scripts that I run on cron every few hours, mostly to help keep disk usage down.

This first one runs tootctl to prune old accounts and media etc. This may not be necessary these days as I believe Mastodon has some built-in pruning now. But I've been running this for a while and it seems to work.

#!/usr/bin/env bash

export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
export RAILS_ENV=production

# Added from
/home/mastodon/live/bin/tootctl accounts prune
#/home/mastodon/live/bin/tootctl media remove --remove-headers --include-follows --days 1
/home/mastodon/live/bin/tootctl media remove --prune-profiles --days 1
/home/mastodon/live/bin/tootctl cache clear
/home/mastodon/live/bin/tootctl statuses remove --days=1
/home/mastodon/live/bin/tootctl media remove --days=1
/home/mastodon/live/bin/tootctl preview_cards remove --days=1
/home/mastodon/live/bin/tootctl media remove-orphans
/home/mastodon/live/bin/tootctl media usage

This compresses images in the cache. You'll need to install jpegoptim and pngquant for this to work.

#!/usr/bin/env bash
cd /home/mastodon/live/public/system/cache
find -name '*.jpg' -print0 | xargs -0 jpegoptim --preserve --threshold=1 --max=45
find -name '*.jpeg' -print0 | xargs -0 jpegoptim --preserve --threshold=1 --max=45

cd /home/mastodon/live/public/system/cache/accounts
find -name '*.png' -print0 | xargs -0 pngquant --ext=.png --force --speed 10 --quality 45-50 --skip-if-larger

cd /home/mastodon/live/public/system/cache/media_attachments
find -name '*.png' -print0 | xargs -0 pngquant --ext=.png --force --speed 10 --quality 45-50 --skip-if-larger

cd /home/mastodon/live/public/system/cache/preview_cards
find -name '*.png' -print0 | xargs -0 pngquant --ext=.png --force --speed 10 --quality 45-50 --skip-if-larger

# Can't really use gif compression as you can't ignore on bigger file size etc
#find -name '*.gif' -print0 | xargs -0 gifsicle -O3 --colors=64 --use-col=web --lossy=100 --batch

Aaaaaaaand... there you have it. Contact me on Mastodon at @josh if you have any questions or need any help, or if you just wanna say hi 👋


I forgot to mention, the only other thing that you kinda might need during the install is an SMTP service for sending emails for sign-ups. I'm pretty sure it's not 100% necessary for a single-user instance, because the installation will set up an admin account for you and you can also use the Mastodon cli tools to create accounts without email confirmation.

But if you want to be able to send emails, you can use Mailgun for free. You can also try SendGrid, but I believe they require you to verify your identity with a credit card.

You can also try setting up SMTP through Gmail, as suggested by KuJoe.

Happy days!


Thanks to @futzle for pointing out that if you don't want literal Nazis and 4chan-like trolls posting the worst stuff on the Internet at you (I found out the hard way), you should probably import a blocklist to block the worst of the worst instances in the fediverse. Here's a good one here called FediNuke. You can import the text file in admin settings under Moderation -> Federation.

UPDATE 2024-03-03: Unfortunately Oracle's free-tier services locked me out of my account without warning, with no way to contact a human for support :(

The steps above will still work, but I would recommend you run your Mastodon instance on your own hardware in-house, or try Google's free tier (though it probably won't have enough storage — maybe try GoToSocial), otherwise (and yes this is not free forever but hey whatever) try to find a cheap VPS on LowEndBox.

Good luck!

If you found this useful, please consider buying me a coffee, as unfortunately coffee isn't free 🥲 ☕