Why?
It’s more a question of ‘Why Not?’.
I was perfectly happy with Iceshrimp.NET but wanted to try something new.
GtS seemed lighter and has hooks into Grafana and Prometheus so I’d be able to mess around with Metrics.
Resources
https://docs.gotosocial.org/en/latest/getting_started/
https://docs.gotosocial.org/en/latest/getting_started/installation/
https://docs.gotosocial.org/en/latest/getting_started/installation/metal/
Preparatory Stuff
Create a PostgreSQL GtS database
In a Terminal, do the following as normal user:
sudo -u postgres psql
Then, (line by line):
create database gotosocial_database with locale 'C.UTF-8' template template0;
create user gotosocial_user with password 'super_long_password';
grant all privileges on database gotosocial_database to gotosocial_user;
ALTER DATABASE gotosocial_database OWNER TO gotosocial_user;
Database Notes:
To list all the databases:
\l
To quit:
\q
To DROP a database (in case something gets bungled):
DROP DATABASE "gotosocial_database";
To DROP a User (in case something gets bungled):
DROP USER "gotosocial_user";
nginx Configuration
In a Terminal, do the following as normal user to create the .conf
file:
sudo nano /etc/nginx/sites-available/GtS
Then add (changing as appropriate):
server {
listen 80;
# No need for an ipv6 address
# listen [::]:80;
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:8888;
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;
}
Check:
sudo nginx -t
Symlink:
sudo ln -s /etc/nginx/sites-available/GtS /etc/nginx/sites-enabled/
Check and reload the webserver:
sudo nginx -t && sudo systemctl reload nginx
UFW
I use UFW to limit which services can connect to the server.
To authorise traffic on Port 8888, first see a verbose list of currently configured connections:
sudo ufw status verbose
Then, allow GtS on Port 8888:
sudo ufw allow 8888 comment "GtS (GoToSocial) Traffic"
To delete first see a list of currently configured connections:
sudo ufw status numbered
Then, delete the appropriate number:
sudo ufw delete #
Certbot
Certbot is a free, open source software tool for automatically using Let’s Encrypt certificates on manually-administrated websites to enable HTTPS.
Certbot is made by the Electronic Frontier Foundation (EFF), a 501(c)3 nonprofit based in San Francisco, CA, that defends digital privacy, free speech, and innovation.
If needed Certbot is a Terminal command away:
sudo apt install certbot python3-certbot-nginx
Then, to generate a certificate:
sudo certbot
After cert has been deployed, re-edit the nginx .conf
file:
sudo nano /etc/nginx/sites-available/GtS
To:
server {
# HTTPS configuration
listen 443 ssl;
# Server
server_name gts.example.com;
# SSL
ssl_certificate /etc/letsencrypt/live/gts.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/gts.example.com/privkey.pem;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# logging
access_log /var/log/nginx/gts.example.com_access.log combined buffer=512k flush=1m;
error_log /var/log/nginx/gts.example.com_error.log warn;
# security
include nginxconfig.io/security.conf;
include /etc/letsencrypt/options-ssl-nginx.conf;
client_max_body_size 40M;
# Proxy to Node
location / {
proxy_pass http://127.0.0.1:8888;
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;
}
}
# HTTP redirect
server {
if ($host = gts.example.com) {
return 301 https://$host$request_uri;
}
listen 80;
server_name gts.example.com;
return 404;
}
Check and reload the webserver:
sudo nginx -t && sudo systemctl reload nginx
Install
Now that there is a database to store the info in, and a running webserver, it’s finally time to install GtS.
Create a directory:
mkdir gotosocial
Move to the newly created directory:
cd gotosocial
Make a ‘storage’ directory:
mkdir storage
Grab the latest GtS bundle:
wget https://github.com/superseriousbusiness/gotosocial/releases/download/v0.17.1/gotosocial_0.17.1_linux_arm64.tar.gz
Unzip everything:
tar -xzf gotosocial_0.17.1_linux_arm64.tar.gz
Tidy up:
rm gotosocial_0.17.1_linux_arm64.tar.gz
Configure
Copy the example config
file before making any changes:
cp example/config.yaml config.yaml
Open it:
nano config.yaml
I made the following adjustments (the descriptors are self-explanatory):
#host: "localhost"
host: "gts.example.com"
#account-domain: ""
account-domain: "example.com"
#bind-address: "0.0.0.0"
bind-address: "localhost"
#Port 8080 is already in use by something else, so change it to something else
#port: 8080
port: 8888
#db-address: ""
db-address: "localhost"
#db-user: ""
db-user: "gotosocial_user"
#db-password: ""
db-password: "super_long_password"
#db-database: "gotosocial"
db-database: "gotosocial_database"
#media-remote-cache-days: 7
media-remote-cache-days: 1
#media-cleanup-every: "24h"
media-cleanup-every: "8h"
Start, Create Account(s)
The moment of truth!
Start the GtS server:
./gotosocial --config-path ./config.yaml server start
Create the first user(s).
https://docs.gotosocial.org/en/latest/getting_started/user_creation/
Personally, I have two accounts:
- An Admin account
- A general non privileged (normal) account
YMMV.
Add an account:
cd ~/gotosocial
./gotosocial --config-path ~/gotosocial/config.yaml \
admin account create \
--username admin_account \
--email admin_account@example.com \
--password 'admin_account_password'
Promote to Admin:
./gotosocial admin account promote --username admin_account --config-path config.yaml
Add another account:
./gotosocial --config-path ~/gotosocial/config.yaml \
admin account create \
--username general_account \
--email general_account@example.com \
--password 'general_account_password'
Do not promote to Admin.
Enable the systemd service
Create the systemd service that will start when the server reboots.
https://raw.githubusercontent.com/superseriousbusiness/gotosocial/main/example/gotosocial.service
sudo nano /etc/systemd/system/gotosocial.service
Run:
sudo systemctl enable --now gotosocial.service
sudo systemctl start gotosocial.service
Check the service status:
sudo systemctl status gotosocial.service
Authentication with the API (get a TOKEN)
I have a couple of bots that need to post autonomously using the API.
This functionality needs an an Auth token:
https://docs.gotosocial.org/en/latest/api/authentication/
Landing Page (config.yaml)
As this is a self-hosted single user instance, rather than the generic GtS homepage I would like my Account Profile to be displayed.
nano gotosocial/config.yaml
#landing-page-user: ""
landing-page-user: "general_account"
sudo systemctl restart gotosocial
Metrics
https://docs.gotosocial.org/en/latest/advanced/metrics/
I’m a big fan of Metrics and Dashboards , so of course I’m going to enable this feature:
Edit the config.yaml
file.
I made the following adjustments (the descriptors are self-explanatory):
nano gotosocial/config.yaml
#metrics-enabled: false
metrics-enabled: true
#metrics-auth-enabled: false
metrics-auth-enabled: true
#metrics-auth-username: ""
metrics-auth-username: "user_login_name"
#metrics-auth-password: ""
metrics-auth-password: "user_login_password"
Restart GtS:
sudo systemctl restart gotosocial
Go to:
https://server.IP/metrics
Now 404 the metrics page from external requests (if desired):
sudo nano /etc/nginx/sites-available/GtS
Add:
# 404 the metrics page from external requests
location /metrics {
return 404;
}
Check and reload the webserver:
sudo nginx -t && sudo systemctl reload nginx
Add to Prometheus
sudo nano /etc/prometheus/prometheus.yml
Add:
# gotosocial/metrics job
- job_name: "gotosocial"
metrics_path: /metrics
scheme: https
basic_auth:
username: "prometheus_login_name"
password: "prometheus_login_password"
static_configs:
- targets:
- gts.example.com
Restart Prometheus:
sudo systemctl restart prometheus
sudo systemctl status prometheus
Go to:
http://server.IP:9090/targets
To see then new endpoint ‘gotosocial’
Add Dashboard to Grafana
http://server.IP:3030/login
UFW
I already mentioned that I use UFW to limit access to the server.
As Prometheus and Grafana were already set up and running, there was no need for me to adjust or add to the existing UFW rules.
Allow Prometheus:
sudo ufw allow from 192.168.0.0/24 to any port 3030 comment "Grafana traffic from LAN only"
Allow Grafana:
sudo ufw allow from 192.168.0.0/24 to any port 9090 comment "Prometheus traffic from LAN only"
Both of the above allow access to Grafana and Prometheus from the LAN only.
I have no interest in viewing my dashboard when away from home or allowing the data to be publicly accessible.
Metrics Notes:
Remember to allow access to the gotosocial_database to the grafana user
sudo -u postgres psql
\connect gotosocial_database;
GRANT CONNECT ON DATABASE "gotosocial_database" TO grafana;
GRANT USAGE ON SCHEMA public TO grafana;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO grafana;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO grafana;
The Scripts
A selection of SQL scripts for the GoToSocial PostgreSQL database.
These three scripts are the routines that I run daily, hourly and monthly.
Why?
All of the Fediverse software that I have used seem to retain too much data for too long.
Personally I see no need to keep the e.g. account details for every account that has passed through my timeline.
Likewise, I do not need to store, archive and backup a huge amount of emoji from various Fediverse instances.
So I remove them, along with what I consider to be other extraneous info.
(The list of data to be removed will probably grow as I dig deeper into the database.)
gotosocial_tidy_daily.sql
WARNING:
This script will:
-
Tidy (DELETE FROM) the gotosocial db accounts table
- Don’t remove any accounts with the following id’s
- Remove any accounts that are not followers
- Remove any accounts that are not followees
- Don’t remove any accounts that are in the blocking table
- Don’t remove any accounts that are in the muting table
-
Tidy (DELETE FROM) the gotosocial db accounts_stats table
- Don’t remove any stats with the following id’s
- Remove any stats that are not followers
- Remove any stats that are not followees
-
Tidy (DELETE FROM) the gotosocial db tokens table
- Keeping the (bot) sessions
-
Tidy (TRUNCATE) the gotosocial db tables
- public.clients
- public.emojis
- public.tombstones
-
Tidy (VACUUM.ANALYZE) the gotosocial db
gotosocial_tidy_hourly.sql
WARNING:
This script will:
-
Tidy (DELETE FROM) the gotosocial db mentions table
- Delete all mentions over n days old
-
General (DELETE FROM) the gotosocial db statuses table
- Per account deletes will be done later
- Delete all statuses over n days old
- Don’t remove any statuses from any accounts in the ‘users’ table
-
Per account (DELETE FROM) the gotosocial db statuses table
- Delete all statuses over n days old
- Probably makes sense to keep this in line with the ‘General’ setting
- Delete from: account_1_username account
- Retain pinned posts
-
Per account (DELETE FROM) the gotosocial db statuses table
- Delete all statuses over n days old
- Probably makes sense to keep account_2_username posts for longer
- Delete from: account_2_username account
- Retain pinned posts
-
Tidy (DELETE FROM) the gotosocial db status_faves table
- Delete all status_faves over n days old
-
Tidy (ANALYZE) any table that has had a DELETE performed upon it
- public.“mentions
- public.“statuses”
- public.“status_faves
gotosocial_tidy_monthly.sql
This script will:
- Perform a VACUUM FULL ANALYZE on the database and only needs to be run occasionally:
Bugs
So far I have found very few bugs and certainly zero application killing ones.
There doesn’t seem to be a way to clear previously authorised sessions i.e. an old browser session, clearing the table stops the application from functioning.
Also, also_known_as
if present prevents the account from being found yet the account can still create content.
Neither of the above would be encountered during normal everyday usage; it’s more me, tinkering with the guts of the database, something a normal person would ever do.