{"id":839,"date":"2023-07-06T20:48:23","date_gmt":"2023-07-06T10:48:23","guid":{"rendered":"https:\/\/www.icemoonprison.com\/blog\/?p=839"},"modified":"2023-08-22T16:06:28","modified_gmt":"2023-08-22T06:06:28","slug":"deploying-the-takahe-fediverse-server-on-debian-11","status":"publish","type":"post","link":"https:\/\/www.icemoonprison.com\/blog\/archives\/839","title":{"rendered":"Deploying the Takah\u0113 Fediverse server on Debian 11"},"content":{"rendered":"\n<p>I have a <a href=\"https:\/\/old.mermaid.town\/\">Mastodon server<\/a>, but I&#8217;m always on the lookout for more lightweight Fediverse software. Recently I was made aware of <a href=\"https:\/\/jointakahe.org\/\">Takah\u0113<\/a>, a Django Fediverse server application written in Python.<\/p>\n\n\n\n<p>The <a href=\"https:\/\/docs.jointakahe.org\/en\/latest\/installation\/\">official installation instructions<\/a> are high-level and require a fair bit of understanding of Linux system administration. In this article I show the individual commands I used to set up my Takah\u0113 instance, <a href=\"https:\/\/cockatoot.city\/\">cockatoot.city<\/a>.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Virtual machine<\/h2>\n\n\n\n<p>The VM I used is a Linode 1 GB shared Nanode running a Debian 11 image.<\/p>\n\n\n\n<p>Since Takah\u0113 requires HTTPS, the VM requires DNS records. Set up A and AAAA records in your DNS hosting interface.<\/p>\n\n\n\n<p>Takah\u0113 sends email, so set up SPF and DKIM records in your DNS hosting interface.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Host setup<\/h2>\n\n\n\n<p>Run everything as root. Substitute italicized text for your own situation.<\/p>\n\n\n\n<p>Set a hostname:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>hostnamectl set-hostname <em>cockatoot<\/em><\/code><\/pre>\n\n\n\n<p>Edit \/etc\/hosts for local DNS resolution:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Add to <code>127.0.0.1<\/code> after <code>localhost<\/code>: <code><em>cockatoot<\/em> <em>cockatoot.city<\/em><\/code><\/li>\n\n\n\n<li>Add to <code>::1<\/code> after <code>localhost<\/code>: <code><em>cockatoot<\/em> <em>cockatoot.city<\/em><\/code><\/li>\n<\/ul>\n\n\n\n<p>Create an admin user that can <code>sudo<\/code> to root. After this step you can log out, log back in as the admin user, and <code>sudo -s<\/code> for the remainder of the steps.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>adduser localadmin\nadduser localadmin sudo\nmkdir ~localadmin\/.ssh\nchmod 700 ~localadmin\/.ssh\nchown localadmin:localadmin ~localadmin\/.ssh<\/code><\/pre>\n\n\n\n<p>Create <code>~localadmin\/.ssh\/authorized_keys<\/code> and put your SSH public key into it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>chown localadmin:localadmin ~localadmin\/.ssh\/authorized_keys\nchmod 600 ~localadmin\/.ssh\/authorized_keys<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Install the Docker system<\/h2>\n\n\n\n<p>Takah\u0113 comes as a Docker image. The standard Debian 11 docker.io package is good enough (but you can install the official Docker packages if you prefer).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apt-get install docker.io<\/code><\/pre>\n\n\n\n<p>Docker creates a bridge interface for containers to talk to the host. Find out what it is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker network inspect bridge<\/code><\/pre>\n\n\n\n<p>The Gateway line in the output lists the host&#8217;s address on the bridge:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"Gateway\": \"172.17.0.1\"<\/code><\/pre>\n\n\n\n<p>Use the shown address in the remaining instructions if yours is different to 172.17.0.1.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Install mail transport agent<\/h2>\n\n\n\n<p>Takah\u0113 relies on email to send password-reset notifications and account confirmations. These instructions will vary depending on your upstream mail transport configuration. I use Fastmail, which allows me to create a specific application password for an SMTP client.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>You may want to have Takah\u0113 talk straight to your smarthost. If this is an option for you, you might not need to configure email on your VM at all, and you can skip the patching of <code>settings.py<\/code> below.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>apt-get install exim4<br>dpkg-reconfigure exim4-config<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Mail sent by smarthost<\/li>\n\n\n\n<li>System name = <em>cockatoot.city<\/em><\/li>\n\n\n\n<li>Visible domain name = <em>cockatoot.city<\/em><\/li>\n\n\n\n<li>smarthost = <em>smtps-proxy.fastmail.com::4465<\/em><\/li>\n\n\n\n<li>Don\u2019t split config<\/li>\n\n\n\n<li>Listen on 127.0.0.1; ::1; 172.17.0.1<\/li>\n\n\n\n<li>Relay for network 172.17.0.0\/16<\/li>\n<\/ul>\n\n\n\n<p>Edit <code>\/etc\/exim4\/passwd.client<\/code> and add the authorization for Fastmail:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>*:MY@FASTMAIL_ACCOUNT:FASTMAIL_APP_PASSWORD<\/code><\/pre>\n\n\n\n<p>Edit <code>\/etc\/email-addresses<\/code>, which translates outgoing email addresses in <code>From<\/code> headers:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root:<em>majormitchell@cockatoot.city<\/em><\/code><\/pre>\n\n\n\n<p>Debian 11 exim4 installations require <a href=\"https:\/\/wiki.debian.org\/Exim#Communicating_with_a_smarthost\">some hand-editing of configuration files<\/a> for smarthost handling. Follow these steps.<\/p>\n\n\n\n<p>Edit <code>\/etc\/aliases<\/code> so that mail to root and localadmin goes upstream:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root: <em>majormitchell@cockatoot.city<\/em>\nlocaladmin: root<\/code><\/pre>\n\n\n\n<p>Reprocess the aliases file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>newaliases<\/code><\/pre>\n\n\n\n<p>Test sending an email now.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Database<\/h2>\n\n\n\n<p>Debian 11 comes with Postgres 13, and Takah\u0113 asks for Postgres 15, so install the Postgres official packages.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apt-get install gnupg<\/code><\/pre>\n\n\n\n<p>Follow the Postgres instructions to <a href=\"https:\/\/www.postgresql.org\/download\/linux\/debian\/\">add the official repository<\/a>. <\/p>\n\n\n\n<p>Install postgres:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apt-get install postgresql<\/code><\/pre>\n\n\n\n<p>Create <code>\/etc\/postgresql\/15\/main\/conf.d\/listen-on-bridge.conf<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>listen_addresses = '127.0.0.1,::1,172.17.0.1'<\/code><\/pre>\n\n\n\n<p>Edit <code>\/etc\/postgresql\/15\/main\/pg_hba.conf<\/code> and add Docker bridge IP range<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>host\tall\tall\t172.17.0.1\/16\tscram-sha-256<\/code><\/pre>\n\n\n\n<p>By default, the postgres user does not have a password (it connects by a socket), so give it a password. Also create the empty takahe database.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo -u postgres psql\n# ALTER USER postgres PASSWORD \u2018<em>POSTGRES_PASSWORD<\/em>\u2019;\n# CREATE DATABASE takahe;\n# \\q<\/code><\/pre>\n\n\n\n<p>Postgres normally listens on TCP port 5432. Check this, and adjust accordingly from now on:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>grep '^port' \/etc\/postgresql\/15\/main\/postgresql.conf\nport = 5432 # (change requires restart)<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Firewall<\/h2>\n\n\n\n<p>None of the services on the VM will be exposed to the outside (except the web server), so you can skip this section (but don&#8217;t).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apt-get install ufw\nufw enable\nufw allow ssh\nufw allow to 172.17.0.0\/16 port <em>5432<\/em> proto tcp\nufw allow to 172.17.0.0\/16 port smtp proto tcp\nufw allow http\nufw allow https<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Web server<\/h2>\n\n\n\n<p>Takah\u0113 needs a web server that can operate in reverse-proxy mode, passing requests on HTTPS port 443 down to the Takah\u0113 webserver container on port 8000.<\/p>\n\n\n\n<p>Install a Let&#8217;s Encrypt certificate.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apt-get install nginx python3-certbot-nginx\ncertbot run --nginx -d <em>cockatoot.city<\/em> -m <em>MY@EMAIL_ADDRESS<\/em> --agree-tos<\/code><\/pre>\n\n\n\n<p>Edit <code>\/etc\/nginx\/sites-enabled\/default<\/code> and modify the <code>location \/ { }<\/code> to point to the yet-to-be-created webserver Docker image:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>location \/ {\n    proxy_set_header Host $host;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_pass http:\/\/172.17.0.2:8000\/; \n}<\/code><\/pre>\n\n\n\n<p>Restart the web server:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl restart nginx<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">S3 object storage<\/h2>\n\n\n\n<p>Takah\u0113 can be configured to store media on Amazon S3-compatible storage. Set up a bucket (here called <em><code>BUCKET<\/code><\/em>) and create an access keypair (<em><code>S3_ACCESS_KEY<\/code><\/em>, <em><code>S3_ACCESS_SECRET<\/code><\/em>).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Takah\u0113 environment<\/h2>\n\n\n\n<p>A number of environment variables need to be passed to the Takah\u0113 containers. It&#8217;s easiest to put them into a file and invoke Docker with the <code>--env-file<\/code> option.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir \/etc\/takahe<\/code><\/pre>\n\n\n\n<p>Edit <code>\/etc\/takahe\/environment<\/code> and fill it with lots of secret information:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>TAKAHE_SECRET_KEY=<em>BIG_LONG_RANDOM_STRING<\/em>\nTAKAHE_MEDIA_BACKEND=s3:\/\/<em>S3_ACCESS_KEY<\/em>:<em>S3_ACCESS_SECRET<\/em>@<em>S3_ENDPOINT_HOST<\/em>\/<em>BUCKET<\/em>\nTAKAHE_MAIN_DOMAIN=<em>cockatoot.city<\/em>\nTAKAHE_EMAIL_SERVER=smtp:\/\/172.17.0.1:25\/\nTAKAHE_EMAIL_FROM=<em>majormitchell@cockatoot.city<\/em>\nTAKAHE_AUTO_ADMIN_EMAIL=<em>majormitchell@cockatoot.city<\/em>\nTAKAHE_USE_PROXY_HEADERS=true\nTAKAHE_CSRF_HOSTS=&#91;\"https:\/\/<em>cockatoot.city<\/em>\"]\nPGHOST=172.17.0.1\nPGUSER=postgres\nPGPORT=<em>543<\/em>2\nPGPASSWORD=<em>POSTGRES_PASSWORD<\/em><\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Install Takah\u0113 image<\/h2>\n\n\n\n<p>Fetch the Takah\u0113 image:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker pull jointakahe\/takahe<\/code><\/pre>\n\n\n\n<p>Create the first Takah\u0113 containers from the image, for the webserver, but don&#8217;t run it yet:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker create --env-file=\/etc\/takahe\/environment --name=webserver jointakahe\/takahe<\/code><\/pre>\n\n\n\n<p>Create the second Takah\u0113 container, for the worker:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker create --env-file=\/etc\/takahe\/environment --name=worker --restart=always jointakahe\/takahe python3 manage.py runstator --liveness-file \/var\/run\/takahe-watchdog<\/code><\/pre>\n\n\n\n<p>Takah\u0113 doesn&#8217;t allow an unauthenticated SMTP relay, so one file inside the container needs to be modified. The webserver container doesn&#8217;t try to send email so it doesn&#8217;t need to be changed.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker cp worker:\/takahe\/takahe\/settings.py \/tmp\/settings.py<\/code><\/pre>\n\n\n\n<p>Edit \/tmp\/settings.py and alter two lines:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>EMAIL_HOST_USER = urllib.parse.unquote(parsed.username) if parsed.username is not None else None<br>EMAIL_HOST_PASSWORD = urllib.parse.unquote(parsed.password) if parsed.password is not None else None<\/code><\/pre>\n\n\n\n<p>And copy the modified file back:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker cp \/tmp\/settings.py worker:\/takahe\/takahe\/settings.py<\/code><\/pre>\n\n\n\n<p>Run, once, the initial database scheme migration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker exec -it worker python3 manage.py migrate<\/code><\/pre>\n\n\n\n<p>Start the two containers:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker start webserver<br>docker start worker<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Try it out<\/h2>\n\n\n\n<p>Go to <em>https:\/\/cockatoot.city\/auth\/signup\/<\/em> and sign up with the address that you set as the <code>TAKAHE_AUTO_ADMIN_EMAIL<\/code> account. You should receive an email with a link to set your password.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Next steps<\/h2>\n\n\n\n<p>To do:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>systemd units to start and stop the containers<\/li>\n\n\n\n<li>Bulk defederate from unwanted instances<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>I have a Mastodon server, but I&#8217;m always on the lookout for more lightweight Fediverse software. Recently I was made aware of Takah\u0113, a Django Fediverse server application written in Python. The official installation instructions are high-level and require a fair bit of understanding of Linux system administration. In this article I show the individual [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":3,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":""},"categories":[1],"tags":[88,91,89,90],"class_list":["post-839","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-fediverse","tag-mastodon","tag-takahe","tag-takahe-2"],"_links":{"self":[{"href":"https:\/\/www.icemoonprison.com\/blog\/wp-json\/wp\/v2\/posts\/839","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.icemoonprison.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.icemoonprison.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.icemoonprison.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.icemoonprison.com\/blog\/wp-json\/wp\/v2\/comments?post=839"}],"version-history":[{"count":6,"href":"https:\/\/www.icemoonprison.com\/blog\/wp-json\/wp\/v2\/posts\/839\/revisions"}],"predecessor-version":[{"id":846,"href":"https:\/\/www.icemoonprison.com\/blog\/wp-json\/wp\/v2\/posts\/839\/revisions\/846"}],"wp:attachment":[{"href":"https:\/\/www.icemoonprison.com\/blog\/wp-json\/wp\/v2\/media?parent=839"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.icemoonprison.com\/blog\/wp-json\/wp\/v2\/categories?post=839"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.icemoonprison.com\/blog\/wp-json\/wp\/v2\/tags?post=839"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}