How to run a fedi instance with GoToSocial for 12 dollars a year

How to run a fedi instance with GoToSocial for 12 dollars a year

The software

We are going to host a fedi instance on a cheap VPS with Debian and GoToSocial. If you don’t know GoToSocial, it is a fedi server software written in Go for small instances with at most a few dozen active users. Here are some facts about it.

Pros:

  • Self contained binary, in principle you don’t need a standalone HTTP server like Nginx;
  • Configuration is all done in a very well documented config file;
  • Great documentation specially for such a new project;
  • Automatically obtains and renews a Let’s Encrypt certificate if not running behind Nginx;
  • Uses between 50MB and 100MB of ram;
  • SQLite (makes backups very easy) or PostgreSQL;
  • Devs provide sane privacy and security defaults, specially useful for inexperienced admins;
  • The already available features work very well.

Cons:

  • Still alpha so some features are lacking, see the roadmap;
  • Not designed for large instances and no clear migration path to Pleroma/Mastodon.

The hardware

Pick a 1 dollar VPS from lowendbox, any will do as long as it has 512MB of ram or more, 256MB could work but I didn’t test. Not all those offers are precisely 1 dollar per month, I bought a RackNerd instance with 512MB of ram for ~10 dollars per year. For single or few user instances GoToSocial should stay between 50MB and 100MB of ram so you might be able to get away with 128MB by using ZRam, Alpine Linux or some other super minimal OS.

The domain

I bought a domain from porkbun, it was 2 dollars for the first year and around 10 dollars for the subsequent years, I can cancel at any time. But you can also get a free domain from freenom, they offer free .tk, .ml, .gq, and .cf domains on a first-come, first-served basis. Freenom will be blacklisted on all email servers but should work fine for fedi and personal sites. In the future I want to look into adding .onion, .eth, .bit and OpenNic domains.

Installing and configuring GoToSocial

sudo adduser gotosocial
sudo -u gotosocial -s
mkdir -p ~/gotosocial/storage/certs
cd ~/gotosocial

Grab the latest version of GoToSocial here, at the moment of writing it was 0.6.0.

wget https://github.com/superseriousbusiness/gotosocial/releases/download/v0.6.0/gotosocial_0.6.0_linux_amd64.tar.gz
tar -zxf gotosocial_0.6.0_linux_amd64.tar.gz

Let’s copy the example config file.

cp ./example/config.yaml .

Now open the config file with your favorite text editor and change the following options. You shouldn’t change the domain related settings after the sever is run for the first time.

# We will run the instance on gts.example.com
# but everyone will see the accounts as user@example.com.
host "gts.example.com"
account-domain: "example.com"

# We will run locally and let nginx forward request to us
bind-address: "localhost"
port 8080

# Backups are just stopping the server and copying a folder
db-type "sqlite"
db-address "gotosocial.db"
storage-local-base-path: "/home/gotosocial/gotosocial/storage"

syslog-enabled: true

First run

./gotosocial --config-path ./config.yaml server start

Create a new user - mind the space at the beginning of the line, this command won’t be saved to history (because it contains a password):

 ./gotosocial --config-path ./config.yaml admin account create --username user --email user@example.com --password 'abc123'
 

And make it admin.

./gotosocial --config-path ./config.yaml admin account promote --username user

Add a systemd service

sudo cp /home/gotosocial/gotosocial/example/gotosocial.service /etc/systemd/system
sudo nano /etc/systemd/system/gotosocial.service
ExecStart=/home/gotosocial/gotosocial/gotosocial --config-path config.yaml server start
WorkingDirectory=/home/gotosocial/gotosocial
sudo systemctl start gotosocial

Installing and configuring Nginx

We are going to run GoToSocial on a domain of its own, gts.example.com, but have the user accounts be @user@example.com, for that we need to redirect the webfinger paths from example.com to gts.example.com.

Configuring Nginx is an easy and well documented procedure, I will refer you to this tutorial on how to setup nginx on debian and another one on how to to setup Let’s Encrypt. Remember to configure example.com and gts.example.com.

Reverse proxy

Configure nginx to forward any request to gts.example.com to our GoToSocial server.

sudo nano /etc/nginx/sites-available/gts.example.com

Your file may look slightly different, the important part is adding the location block to the server block with the SSL configurations (the one listening on port 443). Requests to port 80 will be automatically redirected here.

server {
  server_name gts.example.com
  location / {
    # set to 127.0.0.1 instead of localhost to work around
	# https://stackoverflow.com/a/52550758
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
  client_max_body_size 40M;
  
  # The rest of our nginx config...
}

Webfinger redirect

sudo nano /etc/nginx/sites-available/example.com

Again, your file may look slightly different, the important part is adding the location blocks to the server block with the SSL configurations (the one listening on port 443). Requests to port 80 will be automatically redirected here.

http {
  server {
	server_name example.com, www.example.com;
	location /.well-known/webfinger {
	  rewrite ^.*$ https://gts.example.org/.well-known/webfinger permanent;
	}
	location /.well-known/nodeinfo {
	  rewrite ^.*$ https://gts.example.org/.well-known/nodeinfo permanent;
	}
    # The rest of our nginx config... 
	}
}

Test and reload

sudo nginx -t
sudo systemctl reload nginx

AppArmor profile

And lastly, a modified AppArmor profile to use our /home/gotosocial installation path.

Save the file below to /etc/apparmor.d/gotosocial then run.

#include <tunables/global>

profile gotosocial flags=(attach_disconnected, mediate_deleted) {
  #include <abstractions/base>
  #include <abstractions/nameservice>

  /home/gotosocial/gotosocial/gotosocial mrix,
  /usr/bin/gotosocial mrix,
  /usr/local/bin/gotosocial mrix,

  owner /home/gotosocial/gotosocial/{,**} r,
  owner /home/gotosocial/gotosocial/storage/** wk,

  # Allow GoToSocial to write logs
  #
  # NOTE: you only need to allow write permissions to /var/log/syslog if you've
  # enabled logging to syslog. Otherwise, you can comment out that line.
  /var/log/gotosocial/* w,
  owner /var/log/syslog w,

  # These directories are not currently used by any of the recommended
  # GoToSocial installation methods, but they may be used in the future and/or
  # for custom installations.
  owner /etc/gotosocial/{,**} r,
  owner /usr/lib/gotosocial/{,**} r,
  owner /usr/share/gotosocial/{,**} r,
  owner /usr/local/etc/gotosocial/{,**} r,
  owner /usr/local/lib/gotosocial/{,**} r,
  owner /usr/local/share/gotosocial/{,**} r,
  owner /var/lib/gotosocial/{,**} r,
  owner /opt/gotosocial/{,**} r,
  owner /run/gotosocial/{,**} r,

  /proc/sys/net/core/somaxconn r,
  /sys/kernel/mm/transparent_hugepage/hpage_pmd_size r,
  owner @{PROC}/@{pid}/cpuset r,

  # TCP / UDP network access
  network inet stream,
  network inet6 stream,
  network inet dgram,
  network inet6 dgram,

  # Allow GoToSocial to send signals to/receive signals from worker processes
  # Allow GoToSocial to receive signals from unconfined processes
  signal (receive) peer=unconfined,
  signal (send,receive) peer=gotosocial,
}
# vim:syntax=apparmor

Now let’s tell systemd about our AppArmor profile.

sudo systemctl stop gotosocial

Open the unit file to add the AppArmor section.

sudo nano /etc/systemd/system/gotosocial.service

This should go on the [Service] section. You can put it at the bottom.

[Service]
# ...
AppArmorProfile=gotosocial

Reload the daemon because we changed a unit file.

sudo systemctl daemon-reload

Start the service back again.

sudo systemctl start gotosocial

From their documentation:

GoToSocial is currently alpha software, and as more features are implemented these security policies may quickly become outdated. You may find that using AppArmor or SELinux causes GoToSocial to fail in unexpected ways until GTS becomes stable.

It’s unlikely that you (or I) will have any problems, but if you do, simply remove the AppArmorProfile section from the systemd unit file.

Conclusion

That’s it, your fedi instance is running on gts.example.com. You can access it with most fedi clients but the GoToSocial project mentions pinafore and Tusky as well supported.

To keep up with updates follow GoToSocial’s official account.

Feel free to follow me at master_cat@gts.catona.cloud.