Merge pull request 'Upgrade Mastodon from 4.3 to 4.7, deploy on new Ubuntu 24.04 VM' (#681) from chore/upgrade_mastodon into master

Reviewed-on: #681
Reviewed-by: Greg <greg@kosmos.org>
This commit was merged in pull request #681.
This commit is contained in:
raucao committed 2026-10-08 13:02:46 +00:00
commit 17285bc2c0
18 files changed
+658 -403

No files matched your search

+4
View File
@@ -0,0 +1,4 @@
{
"name": "mastodon-4",
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqBxz0HTAxiUU6VoTTMNj\nonS9GU/RDCq5rIxGd9n89xOoDVb59CgThYgjpthn6T8s1hSkS2Jgi+52S9vlkmXC\nrdr+YhTvqcRuB3w+OMxkaWAwcF6q/c06CzpelyKZ+K9Y1mE7jDVqy9filmZ+p893\nQ5ta4iBg5eE6zsjtVMeTALmsmlwR70vPzZj+VhDeg/TprhFzr44+OB9QNZdFRXSH\n3o0DNhWSvoxUGrt6BOvaNcofYr5XkgP9TLuUZ5p2IZmW58PLSSbTXzPEhdjqACJm\nfCl0ASTHlzbvyTA7bglWuS4HN+VldCts3Y9gVNQ3h6cxfL2aDbWG0Yx2qhAZCOMp\n2wIDAQAB\n-----END PUBLIC KEY-----\n"
}
+55 -48
View File
@@ -1,114 +1,121 @@
{
"id": "mastodon",
"active_record_encryption_deterministic_key": {
"encrypted_data": "2ik8hqK7wrtxyC73DLI8FNezZiWp2rdjwaWZkTUFRj+iwvpSrGVEwMx6uxDI\nWa7zF3p/\n",
"iv": "XMp6wqwzStXZx+F3\n",
"auth_tag": "vloJOLqEcghfQXOYohVVlg==\n",
"encrypted_data": "M7PHYe8qx7TUXpbNMS8slE6p+Naq3WhGklQty8oUJ86cA0hVryqbSySfgBm7\nuEKhTBjO\n",
"iv": "tApFi3rs15Y1sCVy\n",
"auth_tag": "YZ75dXuxepIm8CK8vOd51A==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"active_record_encryption_key_derivation_salt": {
"encrypted_data": "Nq/rHayMYmT/82k3tJUKU8YTvDKUKLoK204aT0CMGZertZaAD3dtA9AkprrA\nPK0D9CdL\n",
"iv": "tn9C+igusYMH6GyM\n",
"auth_tag": "+ReZRNrfpl6ZDwYQpwm6dw==\n",
"encrypted_data": "raLTVbWRr8KRtSL9u2hoZhlcBNzR4qzGssSngIjpVN91ueJF3KRYTf1lyd6O\nt46Il9Ye\n",
"iv": "Jhl+LvZlCmJoxMVP\n",
"auth_tag": "3RgdNDtaH4eiiQfNHeljTA==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"active_record_encryption_primary_key": {
"encrypted_data": "UEDMuKHgZDBhpB9BwbPmtdmIDWHyS9/bSzaEbtTRvLcV8dGOE5q9lDVIIsQp\n2HE0c92p\n",
"iv": "tnB0pQ3OGDne3mN/\n",
"auth_tag": "kt234ms+bmcxJj/+FH/72Q==\n",
"encrypted_data": "nP/pdfTk1VGE+sfAbMq3FN5tyTI4Srpj/szcPDYOU/zfQFRQ3omjSfvOtHFS\nN9XQYPoU\n",
"iv": "R4JdQNPjOfqBGUzC\n",
"auth_tag": "BW+GO+mX2vpNXLOk3wlcKw==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"paperclip_secret": {
"encrypted_data": "AlsnNTRF6GEyHjMHnC4VdzF4swMlppz/Gcp1xr0OuMEgQiOcW1oSZjDRZCRV\nmuGqZXZx64wqZyzTsJZ6ayCLsmWlPq6L21odHWyO+P/C5ubenSXnuCjpUn3/\nHs8WLX3kwVmqCRnVgDl2vEZ5H4XedSLr7R7YM7gQkM0UX4muMDWWnOTR8/x/\ni1ecwBY5RjdewwyR\n",
"iv": "RWiLePhFyPekYSl9\n",
"auth_tag": "sUq4ZX9CFKPbwDyuKQfNLQ==\n",
"encrypted_data": "plu8NMS/EuYAOxepD1lHbfVnzDcwmqFy1LhUKKUhqiQUlanzlZ2kYga8dy0D\n8s1XcVpw8Ei8Pz3LOjuTNfi/gE6yvinbJpxXFRgy2r6iUmoTDaSyk3wyybSN\nQkPPr5p79sJiybtJbgJZSLSylxswp0zsXYNiomoMXaxkGVoLRAEnZ18yKHrR\nzr6EbJp9IMDVOhQe\n",
"iv": "dyThHZkYejBTYV7s\n",
"auth_tag": "mjAiHvv40dcS5uDMz+CfGQ==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"secret_key_base": {
"encrypted_data": "K5CmIXFa9mS4/dODBQAN9Bw0SFpbLiZAB8ewiYpkB8NDXP6X/BX8aDjW2Y4F\ncMvpFyiFldRBhrh1MSKTVYQEoJ3JhlNL9HCdPsAYbBEW70AuEBpHvOtD5OxH\nqgbH4Reuk6JX5AI8SwDD3zGrdT12mTFVNgSujzuZMvpi1Sro2HtRGAkjmnaa\nMGKrBV21O1CREJJg\n",
"iv": "/yMMmz1YtKIs5HSd\n",
"auth_tag": "WXgIVWjIdbMFlJhTD5J0JQ==\n",
"encrypted_data": "+3rZASvdx2B8if9UxJCTJC8OoaOLink/6muPcRv7DNedqF2fmAajI3sJuKYB\nslLUTweW3T+IVHnzT8RiNiY8mZ81ivkyQwqtl0qnfwrWTDB3auPdlZTIxSfn\nDz4a/Z4it8ewrPXeFfsZgxJebG313JB4EQN/LBHgJMBKkVeuDS4tl1zwSt4C\njEv01JO/7HXLVdGu\n",
"iv": "+CWPVenB0YLeUVF+\n",
"auth_tag": "0ZDAgVX7k/1JNDvzK7/Hxw==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"otp_secret": {
"encrypted_data": "OPLnYRySSIDOcVHy2A5V+pCrz9zVIPjdpAGmCdgQkXtJfsS9NzNtxOPwrXo6\nuQlV9iPjr1Y9ljGKYytbF0fPgAa5q6Z1oHMY9vOGs/LGKj8wHDmIvxQ+Gil1\nC+dZEePmqGaySlNSB/gNzcFIvjBH3mDxHJJe9hDxSv5miNS9l9f3UvQeLP2M\nU7/aHKagL9ZHOp/d\n",
"iv": "wqJBLdZhJ7M/KRG9\n",
"auth_tag": "dv5YyZszZCrRnTleaiGd4A==\n",
"encrypted_data": "8xVxIgJLV4fM2DvNBeVwUTEuyf9TsAgiWrKgoj/dKmFriiZTMrY40qkoPJbP\nEI3NCK8Pvt1MF5izT/6jzxEjXEZRo3kWk1x3QqIbLmo/z6k4GC0JhAO8xDKL\nopGQBOj0Bjte3xsz/vBFCgmqpC1WQe/FpCyFVT1r0uVwAUkMiM/7McnRVmKJ\nPS59QJuuV1DtI6b+\n",
"iv": "j2tC9oc6U6bjV5BJ\n",
"auth_tag": "/Hi9sxV3aN6BR5Ixdf78DQ==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"aws_access_key_id": {
"encrypted_data": "A1/gfcyrwT6i9W6aGTJ8pH4Dm4o8ACDxvooDroA/2N0szOiNyiYX\n",
"iv": "JNvf21KhdM3yoLGt\n",
"auth_tag": "2xaZql1ymPYuXuvXzT3ymA==\n",
"encrypted_data": "71TLwj7sYmHAm/cEX6lKE8MWDlceW5S0hrPLNVzVZ7IimjTNYf4g\n",
"iv": "DoSmqv6owgIL8+be\n",
"auth_tag": "ZcO902nm+MbP4+mwLACDvQ==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"aws_secret_access_key": {
"encrypted_data": "T1tc01nACxhDgygKaiAq3LChGYSgmW8LAwr1aSxXmJ5D2NtypJDikiHrJbFZ\nfWFgm1qe4L8iD/k5+ro=\n",
"iv": "FDTPQQDLUMKW7TXx\n",
"auth_tag": "msY6PFFYhlwQ0X7gekSDiw==\n",
"encrypted_data": "6VOYHuZ27cqx5rfrWeKfUyX6lpSI9/o7MXuj/ah7ZTKSwx6GUbzbe3hzZJcM\nzlDjF8WkIkOwUt/yK5I=\n",
"iv": "F7wyRALeMvPec7i6\n",
"auth_tag": "I27zZeNdqetp9+Pvor7FVw==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"ldap_bind_dn": {
"encrypted_data": "C/YNROVyOxmR4O2Cy52TX41EKli2bCOMzwYD+6Hz/SiKkgidnKUHlvHlbTDq\nkWwlRDM2o8esOCKaEAGPNWcNc9IHlaSsfwhr4YWnwe0=\n",
"iv": "QCQF0+vH+//+nDxr\n",
"auth_tag": "a0PbyO/7wjufqH2acDCqmQ==\n",
"encrypted_data": "d5AxFLbM5mkQ42Ev3jLF6divhVGRS29pf4V1HLT/EZoeTaY0Ag6+aRujP9ri\nHDi5j+VRaKNMtfK1NzQKl6XiCj0oGdO1EsRynpxXyJ0=\n",
"iv": "T4Qz2KrB30La0dj/\n",
"auth_tag": "4I+ySAVvfFDDnfipb+JjDA==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"ldap_password": {
"encrypted_data": "SqwKeiyzfvvZGqH5gi35BdW3W+Fo/AQQjso1Yfp2XA==\n",
"iv": "md2/etFJ1r/BKaYg\n",
"auth_tag": "OlCCOoYSD7ukdH2yWCd6KA==\n",
"encrypted_data": "2V7nesfImnY6DooFctBupXKyexLqTUUoY5M7wQE0FA==\n",
"iv": "wjRF6W7JkUUS6Qn8\n",
"auth_tag": "PhuKjWIla3yFCprFgzxilA==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"smtp_user_name": {
"encrypted_data": "0kzppmSSUg7lEyYnI5a0nf+xO0vSVx88rbxI+niIdzFOOBKSIL6uVHJ340dw\nMQ==\n",
"iv": "lQR77ETTtIIyaG1r\n",
"auth_tag": "smF2HRg8WdmD+MWwkT3TqA==\n",
"encrypted_data": "rQR5ut5VCbQf3dLz6els3BSU3Lj1dZp0k6EaEZnM2E41HrQbMCAgMWrepTaO\nCQ==\n",
"iv": "5e/KzhAz6ALZzxOm\n",
"auth_tag": "wBJLKVHyB1JKeZ9hS8uUIQ==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"smtp_password": {
"encrypted_data": "1i0m9qiZA/8k8fMKo+04uyndl1UhagtHweBFICIorWALkB68edjb8OhUDxv9\nTubiXYRC\n",
"iv": "IU2x4ips9HWmKoxi\n",
"auth_tag": "BZJTDfPBvt8cf6/MbKzUJQ==\n",
"encrypted_data": "AYFleIGUXYZGqSXoDhJB9CG8jNlM1libXzxByDiOPxJH3q5vpGYl+ZThGQZ3\n1HFfKhR/\n",
"iv": "Qrvt1HLaHBqHwApE\n",
"auth_tag": "auqwRDScQfGe42Olhj/y7g==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"vapid_private_key": {
"encrypted_data": "+LmySMvzrV3z2z7BmJG9hpvkL06mGc87RG20XQhhdAJ2Z/5uMMjev2pUf7du\ntv2qvDJAimhkZajuDGL9R3eq\n",
"iv": "Mg7NhPl31O6Z4P+v\n",
"auth_tag": "qYWPInhgoWAjg0zQ+XXt5w==\n",
"encrypted_data": "PRNWILa/ipj00zXrCknF0PZlpvPPPNtGgPuJS61Q8I4+XK517cAaDQypQFUa\nznm2KfQvHWDmQPRfS/oRYIk1\n",
"iv": "EBEzvMfR8J6X8o9J\n",
"auth_tag": "qECmv9fOw2PKgbxIYaWEnw==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"vapid_public_key": {
"encrypted_data": "NOyc+Cech9qG2HhnhajDaJMWd1OU5Rp6hws6i4xF5mLPePMJ9mJTqzklkuMK\npYSEdtcxA3KmDt1HrFxfezYUc9xO9pvlm0BPA7XAFmF/PU7/AJbFqgPU6pX/\ntSDLSdFuMB3ky+cl4DJi+O4=\n",
"iv": "rgUglYiHB/mhqGha\n",
"auth_tag": "DEX7hdNsNLi/LIrMkdUe/Q==\n",
"encrypted_data": "A+yqJ64L2rrqSJ4WyCVh6rXJG9aMSyr/+11pvb8w8al3Ei69YoeX1DeWeD6J\nXgogGJDCoucoCAlcx9tFhmWpR9050d+d2Fuz2RvvElUYUACdSpzlKYcJ1fkl\nRSjUVH69EePjg3GTxlkCDiA=\n",
"iv": "hEjJ7NWlRjlGtFbQ\n",
"auth_tag": "2WGbglPqBR00UINDVr38hA==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"s3_key_id": {
"encrypted_data": "rPVzrYYIbcM+ssVpdL6wpCTdzLIEKXke1+eMlPLMG2gPuoh+W3eO3nFGb/s2\n",
"iv": "/qI8F9cvnfKG7ZXE\n",
"auth_tag": "z1+MPdkO/+SCaag2ULelPg==\n",
"encrypted_data": "Jln2B+YjH6rWfgVzMmDg6oBB1PEZ0stiNFKEpTTSkht68oGXPVYOm40m7+/Q\n",
"iv": "Sz7de5LhoH6FFs93\n",
"auth_tag": "aZJjE5GCPy2QAFCHhnp6oQ==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"s3_secret_key": {
"encrypted_data": "RMnB9kZ+slbQXfpo0udYld6S1QqBxqM1YbszdLfSAdKK9I0J3Kmvh/CQ5Fbx\nyov6LClmsl1rjtH16r7cY32M4Woq+6miERdtecyDrrYkNHz0xkA=\n",
"iv": "pO7bm3aOtjuwYjG/\n",
"auth_tag": "SRvn4z1+Vd5VAGgjG64s+Q==\n",
"encrypted_data": "Bjpc0XCQyPq3ZVggp2GHPDUHiOPX3UH6tNFeJE9lkqL7NSRmQ5r/Do7oDjQB\nT2Es7NL3rFLdVoV6tRRchkUDFzgyr2eSvEHkproU44FTTFmgDN0=\n",
"iv": "HEkOIrKktAezN1AK\n",
"auth_tag": "s54GLjslaf0e30MzW3kY5g==\n",
"version": 3,
"cipher": "aes-256-gcm"
},
"repo_deploy_key": {
"encrypted_data": "hI6a++CCP2/wn5OM86neYUyzFlvD1/w3VaDPB93cPkCqp7UJlj4mOl1J3Gpd\n4Tej/dpsEFiEWP2D15bMHPm5eD8YtD0iueRsTs7TVsgAwWcPIkBV52QHKjoB\nyn6FlA8f6wjF1D4IKhdSbBl2Se0gFPHT3FMy6NkV0dyUB60umMZhaQTS0h9+\ngbi6AYYQSxs3YkfAcQa7iyAXWSw1M4EsrrN2EQ14KN5RTjv24hgNGgUnINMa\nc7dVnz31wIdLfLZy2SlqNQqgwyz8KRXnDWdwnbvwNrJ1HMwNARabDnySUTB9\n03nExQnxG+c3+ioC7KSO++QATC9m0iWjx93m7S7VcbCwdpBZsswztQ/ix8AL\n6CddyLpcK80QrFPrSb2UjFtZuLNuX/Cbzrmm73MYqi/WKfWstKnyFBfkAJUA\nK8HnFU6gmvxyrgQp5ZI/1FNegr67sQlE0dhTYUcps5ZhpJ7ppJX4Fb3yq//8\n8NXEVxGrEwxCAMQEU5HlbBLXTLcTtLhujppPkdp4nYLdiWIMGIqnvOoeJi4n\nTg18xwdMN9G0OMH818Pj/LRBVfxzStbd1ZkemQw6\n",
"iv": "8d8CQGLoNlIyZT6h\n",
"auth_tag": "J9K5wCJ0bZl5uI2PM9+gag==\n",
"version": 3,
"cipher": "aes-256-gcm"
}
+1 -1
Submodule nodes updated: b3b5042655...58e8fb83fd.
+4 -1
View File
@@ -1,8 +1,11 @@
name "mastodon"
default_attributes 'kosmos-mastodon' => {
'deploy' => true
}
run_list %w(
role[postgresql_client]
kosmos-mastodon::libretranslate
kosmos-mastodon
kosmos-mastodon::backup
)
@@ -298,7 +298,9 @@ execute "bundle install" do
environment deploy_env
user deploy_user
cwd deploy_path
command "bundle install --without development,test --deployment"
command "bundle config set --local deployment true && " \
"bundle config set --local without 'development test' && " \
"bundle install"
end
execute 'rake db:migrate' do
@@ -1,13 +1,37 @@
node.default["kosmos-mastodon"]["repo"] = "https://gitea.kosmos.org/kosmos/mastodon.git"
node.default["kosmos-mastodon"]["revision"] = "production-4.3"
node.default["kosmos-mastodon"]["repo"] = "git@gitea.kosmos.org:kosmos/mastodon.git"
node.default["kosmos-mastodon"]["revision"] = "production-4.7"
node.default["kosmos-mastodon"]["directory"] = "/opt/mastodon"
node.default["kosmos-mastodon"]["bind_ip"] = "127.0.0.1"
node.default["kosmos-mastodon"]["app_port"] = 3000
node.default["kosmos-mastodon"]["streaming_port"] = 4000
node.default["kosmos-mastodon"]["domain"] = "kosmos.social"
node.default["kosmos-mastodon"]["alternate_domains"] = []
node.default["kosmos-mastodon"]["redis_url"] = "redis://localhost:6379/0"
node.default["kosmos-mastodon"]["sidekiq_threads"] = 25
# Only run the Mastodon deployment (code, build, migrations, services) when this
# is true. Set to false to only install the runtime dependencies.
node.default["kosmos-mastodon"]["deploy"] = true
# Only check out and build the application (no migrations, no services) when
# this is true. Implied by `deploy`. Useful to pre-stage a deployment without
# touching the database.
node.default["kosmos-mastodon"]["build"] = true
# Runtime versions
node.default["kosmos-mastodon"]["nodejs_version"] = "24.21.0"
node.default["kosmos-mastodon"]["ruby_version"] = "4.0.7"
node.default["kosmos-mastodon"]["ruby_build_version"] = "v20260924"
# SSH deploy key access to the (private) repository. The private key is stored
# in the credentials/mastodon data bag as `repo_deploy_key`; this is the pinned
# host key of gitea.kosmos.org.
node.default["kosmos-mastodon"]["gitea_ssh_host_key"] =
"gitea.kosmos.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJycWc3U9P/6BzE0HcPiTdmaDN8zKRx+0/jGXYuKiwx7"
# External Redis cluster (see the kosmos_redis cookbook)
node.default["kosmos-mastodon"]["redis_server_role"] = "redis_server"
node.default["kosmos-mastodon"]["redis_port"] = 6379
node.default["kosmos-mastodon"]["redis_db"] = 2
node.default["kosmos-mastodon"]["allowed_private_addresses"] = "127.0.0.1"
node.default["kosmos-mastodon"]["onion_address"] = nil
@@ -25,6 +49,10 @@ node.default["kosmos-mastodon"]["sso_account_reset_password_url"] = "https://acc
node.default["kosmos-mastodon"]["sso_account_resend_confirmation_url"] = "https://accounts.kosmos.org/users/confirmation/new"
node.default["kosmos-mastodon"]["default_locale"] = "en"
# From Mastodon 4.4 on, DEFAULT_LOCALE no longer overrides the browser language
# of unauthenticated users unless this is set to true.
node.default["kosmos-mastodon"]["force_default_locale"] = true
# Mastodon 4.6 introduced optional email subscriptions which can cause
# additional outgoing mail/costs. Disabled by default.
node.default["kosmos-mastodon"]["disable_email_subscriptions"] = true
node.default["kosmos-mastodon"]["libre_translate_endpoint"] = nil
node.override["redisio"]["version"] = "6.2.6"
@@ -6,11 +6,8 @@ description 'Installs/Configures Mastodon'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version '0.2.1'
depends 'backup'
depends 'elasticsearch'
depends 'java'
depends 'firewall'
depends 'redisio'
depends 'postgresql'
depends 'kosmos-nodejs'
depends 'kosmos_openresty'
@@ -1,17 +0,0 @@
#
# Cookbook Name:: kosmos-mastodon
# Recipe:: backup
#
postgresql_data_bag_item = data_bag_item('credentials', 'postgresql')
unless node.chef_environment == "development"
node.override['backup']['s3']['keep'] = 1
node.override["backup"]["postgresql"]["host"] = "pg.kosmos.local"
node.override["backup"]["postgresql"]["databases"]["mastodon"] = {
username: "mastodon",
password: postgresql_data_bag_item['mastodon_user_password']
}
include_recipe "backup"
end
@@ -0,0 +1,193 @@
#
# Cookbook Name:: kosmos-mastodon
# Recipe:: build
#
# Checks out and builds the application without running migrations or starting
# any services, so a deployment can be pre-staged before the maintenance
# window. The build is skipped while the checked-out revision is unchanged.
#
require 'uri'
postgresql_credentials = data_bag_item('credentials', 'postgresql')
mastodon_path = node["kosmos-mastodon"]["directory"]
mastodon_user = "mastodon"
mastodon_home = "/home/#{mastodon_user}"
ruby_version = node["kosmos-mastodon"]["ruby_version"]
ruby_path = "/opt/ruby_build/builds/#{ruby_version}"
# External Redis cluster (see the kosmos_redis cookbook)
redis_host = search(:node, "role:#{node['kosmos-mastodon']['redis_server_role']}").first&.dig("knife_zero", "host")
if redis_host.nil?
Chef::Log.fatal("No node found with '#{node['kosmos-mastodon']['redis_server_role']}' role. Stopping here.")
return
end
redis_password = URI.encode_www_form_component(data_bag_item('credentials', 'redis')['password'])
redis_url = "redis://:#{redis_password}@#{redis_host}:#{node['kosmos-mastodon']['redis_port']}/#{node['kosmos-mastodon']['redis_db']}"
rails_env = node.chef_environment == "development" ? "development" : "production"
deploy_env = {
# FIXME: /usr/bin was missing from PATH when running `yarn install`
"PATH" => "#{ruby_path}/bin:/usr/bin:$PATH",
"HOME" => mastodon_home,
"RAILS_ENV" => rails_env,
"NODE_ENV" => rails_env,
"COREPACK_ENABLE_DOWNLOAD_PROMPT" => "0"
}
# Skip the build while the checked-out revision is unchanged
build_uptodate = "test -f #{mastodon_path}/tmp/built-revision && " \
"test \"$(cat #{mastodon_path}/tmp/built-revision)\" = \"$(git -C #{mastodon_path} rev-parse HEAD)\""
credentials = data_bag_item('credentials', 'mastodon')
# The repository is private; clone it with a read-only SSH deploy key kept in
# the mastodon user's home (outside the clone destination).
directory "#{mastodon_home}/.ssh" do
owner mastodon_user
group mastodon_user
mode "0700"
end
file "#{mastodon_home}/.ssh/id_ed25519" do
# OpenSSH's PEM parser rejects a private key without a trailing newline
content lazy { credentials["repo_deploy_key"].to_s.chomp + "\n" }
owner mastodon_user
group mastodon_user
mode "0600"
sensitive true
end
file "#{mastodon_home}/.ssh/known_hosts" do
content "#{node['kosmos-mastodon']['gitea_ssh_host_key']}\n"
owner mastodon_user
group mastodon_user
mode "0644"
end
file "#{mastodon_home}/.ssh/config" do
content <<-EOF
Host gitea.kosmos.org
IdentityFile #{mastodon_home}/.ssh/id_ed25519
IdentitiesOnly yes
StrictHostKeyChecking yes
UserKnownHostsFile #{mastodon_home}/.ssh/known_hosts
EOF
owner mastodon_user
group mastodon_user
mode "0600"
end
# Chef's git resource silently skips cloning when the destination is non-empty
# and not a git clone, so make sure we start from a clean directory.
execute "clear non-git repository directory" do
command "find #{mastodon_path} -mindepth 1 -delete"
only_if { ::Dir.exist?(mastodon_path) && !::File.exist?("#{mastodon_path}/.git") }
end
git mastodon_path do
user mastodon_user
group mastodon_user
repository node["kosmos-mastodon"]["repo"]
revision node["kosmos-mastodon"]["revision"]
environment "GIT_SSH_COMMAND" =>
"ssh -i #{mastodon_home}/.ssh/id_ed25519 -o IdentitiesOnly=yes " \
"-o StrictHostKeyChecking=yes -o UserKnownHostsFile=#{mastodon_home}/.ssh/known_hosts"
end
ldap_config = {
host: "ldap.kosmos.local",
port: 389,
method: "plain",
base: "ou=kosmos.org,cn=users,dc=kosmos,dc=org",
bind_dn: credentials["ldap_bind_dn"],
password: credentials["ldap_password"],
uid: "cn",
mail: "mail",
search_filter: "(&(|(cn=%{email})(mail=%{email}))(serviceEnabled=mastodon))",
uid_conversion_enabled: "true",
uid_conversion_search: "-",
uid_conversion_replace: "_"
}
template "#{mastodon_path}/.env.#{rails_env}" do
source "env.erb"
mode "0640"
owner mastodon_user
group mastodon_user
sensitive true
variables redis_url: redis_url,
domain: node["kosmos-mastodon"]["domain"],
alternate_domains: node["kosmos-mastodon"]["alternate_domains"],
active_record_encryption_deterministic_key: credentials["active_record_encryption_deterministic_key"],
active_record_encryption_key_derivation_salt: credentials["active_record_encryption_key_derivation_salt"],
active_record_encryption_primary_key: credentials["active_record_encryption_primary_key"],
paperclip_secret: credentials['paperclip_secret'],
secret_key_base: credentials['secret_key_base'],
ldap: ldap_config,
smtp_login: credentials['smtp_user_name'],
smtp_password: credentials['smtp_password'],
smtp_from_address: "mail@#{node['kosmos-mastodon']['domain']}",
s3_endpoint: node["kosmos-mastodon"]["s3_endpoint"],
s3_region: node["kosmos-mastodon"]["s3_region"],
s3_bucket: node["kosmos-mastodon"]["s3_bucket"],
s3_alias_host: node["kosmos-mastodon"]["s3_alias_host"],
aws_access_key_id: credentials['s3_key_id'],
aws_secret_access_key: credentials['s3_secret_key'],
vapid_private_key: credentials['vapid_private_key'],
vapid_public_key: credentials['vapid_public_key'],
db_pass: postgresql_credentials['mastodon_user_password'],
db_host: "pg.kosmos.local",
sso_account_sign_up_url: node["kosmos-mastodon"]["sso_account_sign_up_url"],
sso_account_reset_password_url: node["kosmos-mastodon"]["sso_account_reset_password_url"],
sso_account_resend_confirmation_url: node["kosmos-mastodon"]["sso_account_resend_confirmation_url"],
default_locale: node["kosmos-mastodon"]["default_locale"],
force_default_locale: node["kosmos-mastodon"]["force_default_locale"],
disable_email_subscriptions: node["kosmos-mastodon"]["disable_email_subscriptions"],
allowed_private_addresses: node["kosmos-mastodon"]["allowed_private_addresses"],
libre_translate_endpoint: node["kosmos-mastodon"]["libre_translate_endpoint"]
notifies :run, "execute[restart mastodon services]", :delayed if node["kosmos-mastodon"]["deploy"]
end
execute "bundle install" do
environment deploy_env.merge("BUNDLE_BUILD__CHARLOCK_HOLMES" => "--with-cxxflags=-std=c++17")
user mastodon_user
cwd mastodon_path
command "bundle config set --local deployment true && " \
"bundle config set --local without 'development test' && " \
"bundle install"
not_if build_uptodate
end
execute "yarn install" do
environment deploy_env
user mastodon_user
cwd mastodon_path
command "yarn install --immutable"
not_if build_uptodate
end
execute "rake assets:precompile" do
environment deploy_env
user mastodon_user
group mastodon_user
cwd mastodon_path
command "bundle exec rake assets:precompile"
not_if build_uptodate
notifies :run, "execute[record built revision]", :immediately
end
# Record the built revision. Runs as the mastodon user so git accepts the repo
# (a root-run `git` would refuse due to dubious ownership).
execute "record built revision" do
user mastodon_user
group mastodon_user
cwd mastodon_path
command "git rev-parse HEAD > tmp/built-revision"
action :nothing
end
@@ -3,316 +3,10 @@
# Recipe:: default
#
node.override["kosmos_nodejs"]["version"] = "18.20.8"
include_recipe "kosmos-mastodon::dependencies"
include_recipe "kosmos-nodejs"
include_recipe "java"
include_recipe 'redisio::default'
include_recipe 'redisio::enable'
include_recipe 'firewall'
# Check out and build the application without touching the database.
include_recipe "kosmos-mastodon::build" if node["kosmos-mastodon"]["build"] || node["kosmos-mastodon"]["deploy"]
elasticsearch_user 'elasticsearch'
elasticsearch_install 'elasticsearch' do
type 'package'
# The current version of the elasticsearch cookbook doesn't like versions
# it doesn't know about. This would still be installing the default (7.17.9)
# on a new machine, but it doesn't upgrade the package
download_url 'https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.7-amd64.deb'
# SHA256
download_checksum '5c588d779023672ba4e315e7cd4db068ac60a38873a35973574a1cae858c2030'
action :install
end
elasticsearch_configure 'elasticsearch' do
allocated_memory node["kosmos-mastodon"]["elasticsearch"]["allocated_memory"]
jvm_options %w(
-XX:+AlwaysPreTouch
-server
-Xss1m
-Djava.awt.headless=true
-Dfile.encoding=UTF-8
-Djna.nosys=true
-XX:-OmitStackTraceInFastThrow
-Dio.netty.noUnsafe=true
-Dio.netty.noKeySetOptimization=true
-Dio.netty.recycler.maxCapacityPerThread=0
-XX:+HeapDumpOnOutOfMemoryError
)
end
elasticsearch_service 'elasticsearch'
postgresql_credentials = data_bag_item('credentials', 'postgresql')
mastodon_path = node["kosmos-mastodon"]["directory"]
mastodon_user = "mastodon"
bind_ip = if node.chef_environment == "production"
node["knife_zero"]["host"]
else
node["kosmos-mastodon"]["bind_ip"]
end
group mastodon_user do
gid 62786
end
user mastodon_user do
comment "mastodon user"
uid 62786
gid 62786
shell "/bin/bash"
home mastodon_path
end
package %w(build-essential imagemagick ffmpeg libxml2-dev libxslt1-dev file git
curl pkg-config libprotobuf-dev protobuf-compiler libidn11
libidn11-dev libjemalloc2 libpq-dev)
ruby_version = "3.3.5"
ruby_path = "/opt/ruby_build/builds/#{ruby_version}"
bundle_path = "#{ruby_path}/bin/bundle"
ruby_build_install 'v20231025'
ruby_build_definition ruby_version do
prefix_path ruby_path
end
execute "systemctl daemon-reload" do
command "systemctl daemon-reload"
action :nothing
end
# mastodon-web service
#
template "/lib/systemd/system/mastodon-web.service" do
source "mastodon-web.systemd.service.erb"
variables user: mastodon_user,
app_dir: mastodon_path,
bind: bind_ip,
port: node["kosmos-mastodon"]["app_port"],
bundle_path: bundle_path
notifies :run, "execute[systemctl daemon-reload]", :immediately
notifies :restart, "service[mastodon-web]", :delayed
end
# mastodon-sidekiq service
#
template "/lib/systemd/system/mastodon-sidekiq.service" do
source "mastodon-sidekiq.systemd.service.erb"
variables user: mastodon_user,
app_dir: mastodon_path,
bundle_path: bundle_path,
sidekiq_threads: node["kosmos-mastodon"]["sidekiq_threads"]
notifies :run, "execute[systemctl daemon-reload]", :immediately
notifies :restart, "service[mastodon-sidekiq]", :delayed
end
# mastodon-sidekiq-scheduler service
#
template "/lib/systemd/system/mastodon-sidekiq-scheduler.service" do
source "mastodon-sidekiq-scheduler.systemd.service.erb"
variables user: mastodon_user,
app_dir: mastodon_path,
bundle_path: bundle_path,
sidekiq_threads: 1
notifies :run, "execute[systemctl daemon-reload]", :immediately
notifies :restart, "service[mastodon-sidekiq-scheduler]", :delayed
end
# mastodon-streaming service
#
template "/lib/systemd/system/mastodon-streaming.service" do
source "mastodon-streaming.systemd.service.erb"
variables user: mastodon_user,
app_dir: mastodon_path,
bind: bind_ip,
port: node["kosmos-mastodon"]["streaming_port"]
notifies :run, "execute[systemctl daemon-reload]", :immediately
notifies :restart, "service[mastodon-streaming]", :delayed
end
rails_env = node.chef_environment == "development" ? "development" : "production"
deploy_env = {
# FIXME: /usr/bin was missing from PATH when running `yarn install`
"PATH" => "#{ruby_path}/bin:/usr/bin:$PATH",
"HOME" => mastodon_path,
"RAILS_ENV" => rails_env,
"NODE_ENV" => rails_env,
"SKIP_POST_DEPLOYMENT_MIGRATIONS" => "true"
}
git mastodon_path do
user mastodon_user
group mastodon_user
repository node["kosmos-mastodon"]["repo"]
revision node["kosmos-mastodon"]["revision"]
# Restart services on deployments
notifies :run, "execute[restart mastodon services]", :delayed
end
execute "restart mastodon services" do
command "true"
action :nothing
notifies :restart, "service[mastodon-web]", :delayed
notifies :restart, "service[mastodon-sidekiq]", :delayed
notifies :restart, "service[mastodon-sidekiq-scheduler]", :delayed
notifies :restart, "service[mastodon-streaming]", :delayed
end
credentials = data_bag_item('credentials', 'mastodon')
ldap_config = {
host: "ldap.kosmos.local",
port: 389,
method: "plain",
base: "ou=kosmos.org,cn=users,dc=kosmos,dc=org",
bind_dn: credentials["ldap_bind_dn"],
password: credentials["ldap_password"],
uid: "cn",
mail: "mail",
search_filter: "(&(|(cn=%{email})(mail=%{email}))(serviceEnabled=mastodon))",
uid_conversion_enabled: "true",
uid_conversion_search: "-",
uid_conversion_replace: "_"
}
template "#{mastodon_path}/.env.#{rails_env}" do
source "env.erb"
mode "0640"
owner mastodon_user
group mastodon_user
sensitive true
variables redis_url: node["kosmos-mastodon"]["redis_url"],
domain: node["kosmos-mastodon"]["domain"],
alternate_domains: node["kosmos-mastodon"]["alternate_domains"],
active_record_encryption_deterministic_key: credentials["active_record_encryption_deterministic_key"],
active_record_encryption_key_derivation_salt: credentials["active_record_encryption_key_derivation_salt"],
active_record_encryption_primary_key: credentials["active_record_encryption_primary_key"],
paperclip_secret: credentials['paperclip_secret'],
secret_key_base: credentials['secret_key_base'],
otp_secret: credentials['otp_secret'],
ldap: ldap_config,
smtp_login: credentials['smtp_user_name'],
smtp_password: credentials['smtp_password'],
smtp_from_address: "mail@#{node['kosmos-mastodon']['domain']}",
s3_endpoint: node["kosmos-mastodon"]["s3_endpoint"],
s3_region: node["kosmos-mastodon"]["s3_region"],
s3_bucket: node["kosmos-mastodon"]["s3_bucket"],
s3_alias_host: node["kosmos-mastodon"]["s3_alias_host"],
aws_access_key_id: credentials['s3_key_id'],
aws_secret_access_key: credentials['s3_secret_key'],
vapid_private_key: credentials['vapid_private_key'],
vapid_public_key: credentials['vapid_public_key'],
db_pass: postgresql_credentials['mastodon_user_password'],
db_host: "pg.kosmos.local",
sso_account_sign_up_url: node["kosmos-mastodon"]["sso_account_sign_up_url"],
sso_account_reset_password_url: node["kosmos-mastodon"]["sso_account_reset_password_url"],
sso_account_resend_confirmation_url: node["kosmos-mastodon"]["sso_account_resend_confirmation_url"],
default_locale: node["kosmos-mastodon"]["default_locale"],
allowed_private_addresses: node["kosmos-mastodon"]["allowed_private_addresses"],
libre_translate_endpoint: node["kosmos-mastodon"]["libre_translate_endpoint"]
notifies :run, "execute[restart mastodon services]", :delayed
end
execute "bundle install" do
environment deploy_env
user mastodon_user
cwd mastodon_path
command "bundle install --without development,test --deployment"
end
execute "yarn install" do
environment deploy_env
user mastodon_user
cwd mastodon_path
command "corepack prepare && yarn install --immutable"
end
execute "rake assets:precompile" do
environment deploy_env
user mastodon_user
group mastodon_user
cwd mastodon_path
command "bundle exec rake assets:precompile"
end
execute "rake db:migrate" do
environment deploy_env
user mastodon_user
group mastodon_user
cwd mastodon_path
command "bundle exec rake db:migrate"
end
service "mastodon-web" do
action [:enable, :start]
end
service "mastodon-sidekiq" do
action [:enable, :start]
end
service "mastodon-sidekiq-scheduler" do
action [:enable, :start]
end
service "mastodon-streaming" do
action [:enable, :start]
end
#
# Delete cached remote media older than 30 days
# Will be re-fetched if necessary
#
systemd_unit 'mastodon-delete-old-media-cache.service' do
content({
Unit: {
Description: 'Delete old Mastodon media cache'
},
Service: {
Type: "oneshot",
WorkingDirectory: mastodon_path,
Environment: "RAILS_ENV=#{rails_env}",
ExecStart: "#{bundle_path} exec bin/tootctl media remove --days 30",
}
})
triggers_reload true
action [:create]
end
systemd_unit 'mastodon-delete-old-media-cache.timer' do
content({
Unit: {
Description: 'Delete old Mastodon media cache'
},
Timer: {
OnCalendar: '*-*-* 00:00:00',
Persistent: 'true'
},
Install: {
WantedBy: 'timer.target'
}
})
triggers_reload true
action [:create, :enable, :start]
end
firewall_rule "mastodon_app" do
port node['kosmos-mastodon']['app_port']
source "10.1.1.0/24"
protocol :tcp
command :allow
end
firewall_rule 'mastodon_streaming' do
port node['kosmos-mastodon']['streaming_port']
source "10.1.1.0/24"
protocol :tcp
command :allow
end
# Run migrations and manage the services.
include_recipe "kosmos-mastodon::deploy" if node["kosmos-mastodon"]["deploy"]
@@ -0,0 +1,97 @@
#
# Cookbook Name:: kosmos-mastodon
# Recipe:: dependencies
#
# Installs everything Mastodon needs to run, without deploying or starting the
# application itself. Can be run ahead of a deployment to shorten downtime.
#
node.override["kosmos_nodejs"]["version"] = node["kosmos-mastodon"]["nodejs_version"]
include_recipe "kosmos-nodejs"
include_recipe "firewall"
elasticsearch_user 'elasticsearch'
# Elasticsearch 7.x ships a bundled JDK and no JAVA_HOME is configured, so no
# system Java is needed (the java cookbook's openjdk recipe no longer supports
# Ubuntu 24.04 anyway).
elasticsearch_install 'elasticsearch' do
type 'package'
# The current version of the elasticsearch cookbook doesn't like versions
# it doesn't know about. This would still be installing the default (7.17.9)
# on a new machine, but it doesn't upgrade the package
download_url 'https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.7-amd64.deb'
# SHA256
download_checksum '5c588d779023672ba4e315e7cd4db068ac60a38873a35973574a1cae858c2030'
action :install
end
elasticsearch_configure 'elasticsearch' do
allocated_memory node["kosmos-mastodon"]["elasticsearch"]["allocated_memory"]
jvm_options %w(
-XX:+AlwaysPreTouch
-server
-Xss1m
-Djava.awt.headless=true
-Dfile.encoding=UTF-8
-Djna.nosys=true
-XX:-OmitStackTraceInFastThrow
-Dio.netty.noUnsafe=true
-Dio.netty.noKeySetOptimization=true
-Dio.netty.recycler.maxCapacityPerThread=0
-XX:+HeapDumpOnOutOfMemoryError
)
end
elasticsearch_service 'elasticsearch'
mastodon_path = node["kosmos-mastodon"]["directory"]
mastodon_user = "mastodon"
mastodon_home = "/home/#{mastodon_user}"
group mastodon_user do
gid 62786
end
user mastodon_user do
comment "mastodon user"
uid 62786
gid 62786
shell "/bin/bash"
home mastodon_home
end
directory mastodon_home do
owner mastodon_user
group mastodon_user
mode "0755"
end
directory mastodon_path do
owner mastodon_user
group mastodon_user
mode "0755"
end
# Mastodon 4.6 dropped ImageMagick in favor of libvips and requires libvips >= 8.13
package %w(build-essential ffmpeg libxml2-dev libxslt1-dev file git
curl pkg-config libprotobuf-dev protobuf-compiler libidn-dev
libjemalloc2 libpq-dev libvips-dev)
ruby_version = node["kosmos-mastodon"]["ruby_version"]
ruby_path = "/opt/ruby_build/builds/#{ruby_version}"
ruby_build_install node["kosmos-mastodon"]["ruby_build_version"]
ruby_build_definition ruby_version do
prefix_path ruby_path
end
# Node 24 ships corepack >= 0.30, for which `corepack prepare` without an
# argument is no longer valid. Enable the shims as root and let yarn pick up
# the version pinned in package.json instead.
execute "corepack enable" do
command "corepack enable"
end
@@ -0,0 +1,240 @@
#
# Cookbook Name:: kosmos-mastodon
# Recipe:: deploy
#
# Runs database migrations and manages the services. Requires the application
# to have been checked out and built by kosmos-mastodon::build. Migrations and
# the service restart run once per checked-out revision.
#
mastodon_path = node["kosmos-mastodon"]["directory"]
mastodon_user = "mastodon"
bind_ip = if node.chef_environment == "production"
node["knife_zero"]["host"]
else
node["kosmos-mastodon"]["bind_ip"]
end
ruby_version = node["kosmos-mastodon"]["ruby_version"]
ruby_path = "/opt/ruby_build/builds/#{ruby_version}"
bundle_path = "#{ruby_path}/bin/bundle"
rails_env = node.chef_environment == "development" ? "development" : "production"
deploy_env = {
# FIXME: /usr/bin was missing from PATH when running `yarn install`
"PATH" => "#{ruby_path}/bin:/usr/bin:$PATH",
"HOME" => "/home/#{mastodon_user}",
"RAILS_ENV" => rails_env,
"NODE_ENV" => rails_env,
"COREPACK_ENABLE_DOWNLOAD_PROMPT" => "0"
}
# Run migrations, restart services and (re)build the search index once per
# checked-out revision, regardless of whether the code was pre-built.
deploy_uptodate = "test -f #{mastodon_path}/tmp/deployed-revision && " \
"test \"$(cat #{mastodon_path}/tmp/deployed-revision)\" = \"$(git -C #{mastodon_path} rev-parse HEAD)\""
execute "systemctl daemon-reload" do
command "systemctl daemon-reload"
action :nothing
end
# mastodon-web service
#
template "/lib/systemd/system/mastodon-web.service" do
source "mastodon-web.systemd.service.erb"
variables user: mastodon_user,
app_dir: mastodon_path,
bind: bind_ip,
port: node["kosmos-mastodon"]["app_port"],
bundle_path: bundle_path
notifies :run, "execute[systemctl daemon-reload]", :immediately
notifies :restart, "service[mastodon-web]", :delayed
end
# mastodon-sidekiq service
#
template "/lib/systemd/system/mastodon-sidekiq.service" do
source "mastodon-sidekiq.systemd.service.erb"
variables user: mastodon_user,
app_dir: mastodon_path,
bundle_path: bundle_path,
sidekiq_threads: node["kosmos-mastodon"]["sidekiq_threads"]
notifies :run, "execute[systemctl daemon-reload]", :immediately
notifies :restart, "service[mastodon-sidekiq]", :delayed
end
# mastodon-sidekiq-scheduler service
#
template "/lib/systemd/system/mastodon-sidekiq-scheduler.service" do
source "mastodon-sidekiq-scheduler.systemd.service.erb"
variables user: mastodon_user,
app_dir: mastodon_path,
bundle_path: bundle_path,
sidekiq_threads: 1
notifies :run, "execute[systemctl daemon-reload]", :immediately
notifies :restart, "service[mastodon-sidekiq-scheduler]", :delayed
end
# mastodon-streaming service
#
template "/lib/systemd/system/mastodon-streaming.service" do
source "mastodon-streaming.systemd.service.erb"
variables user: mastodon_user,
app_dir: mastodon_path,
bind: bind_ip,
port: node["kosmos-mastodon"]["streaming_port"]
notifies :run, "execute[systemctl daemon-reload]", :immediately
notifies :restart, "service[mastodon-streaming]", :delayed
end
execute "restart mastodon services" do
command "systemctl restart mastodon-web mastodon-sidekiq mastodon-sidekiq-scheduler mastodon-streaming"
action :nothing
end
# Populate the Elasticsearch indices in the background. The indices and
# mappings are created synchronously during the deployment; this unit only does
# the (potentially very long) import, so it is started without blocking. Declared
# before the migration chain below because that chain starts it.
systemd_unit 'mastodon-search-deploy.service' do
content({
Unit: {
Description: 'Populate the Mastodon search index'
},
Service: {
Type: "oneshot",
User: mastodon_user,
WorkingDirectory: mastodon_path,
Environment: "RAILS_ENV=#{rails_env}",
ExecStart: "#{bundle_path} exec bin/tootctl search deploy",
TimeoutStartSec: "21600",
}
})
triggers_reload true
action [:create]
end
# Mastodon 4.4+ splits migrations into pre- and post-deployment phases.
# Pre-deployment migrations must run before the services are (re)started.
execute "rake db:migrate (pre-deployment)" do
environment deploy_env.merge("SKIP_POST_DEPLOYMENT_MIGRATIONS" => "true")
user mastodon_user
group mastodon_user
cwd mastodon_path
command "bundle exec rake db:migrate"
timeout 21_600
not_if deploy_uptodate
notifies :run, "execute[restart mastodon services]", :immediately
notifies :run, "execute[rake db:migrate (post-deployment)]", :immediately
end
execute "rake db:migrate (post-deployment)" do
environment deploy_env
user mastodon_user
group mastodon_user
cwd mastodon_path
command "bundle exec rake db:migrate"
timeout 21_600
action :nothing
notifies :run, "execute[tootctl search deploy (create indices)]", :immediately
end
# Create or upgrade the Elasticsearch indices and mappings without importing
# data, so that search does not fail on a missing index. The (potentially very
# long) import is deferred to a systemd unit started in the background below.
execute "tootctl search deploy (create indices)" do
environment deploy_env
user mastodon_user
group mastodon_user
cwd mastodon_path
command "#{bundle_path} exec bin/tootctl search deploy --no-import"
timeout 3_600
action :nothing
notifies :run, "execute[start mastodon search deploy]", :immediately
notifies :run, "execute[record deployed revision]", :immediately
end
execute "start mastodon search deploy" do
command "systemctl start --no-block mastodon-search-deploy.service"
action :nothing
end
# Record the deployed revision. Runs as the mastodon user so git accepts the
# repo (a root-run `git` would refuse due to dubious ownership).
execute "record deployed revision" do
user mastodon_user
group mastodon_user
cwd mastodon_path
command "git rev-parse HEAD > tmp/deployed-revision"
action :nothing
end
service "mastodon-web" do
action [:enable, :start]
end
service "mastodon-sidekiq" do
action [:enable, :start]
end
service "mastodon-sidekiq-scheduler" do
action [:enable, :start]
end
service "mastodon-streaming" do
action [:enable, :start]
end
#
# Delete cached remote media older than 30 days
# Will be re-fetched if necessary
#
systemd_unit 'mastodon-delete-old-media-cache.service' do
content({
Unit: {
Description: 'Delete old Mastodon media cache'
},
Service: {
Type: "oneshot",
WorkingDirectory: mastodon_path,
Environment: "RAILS_ENV=#{rails_env}",
ExecStart: "#{bundle_path} exec bin/tootctl media remove --days 30",
}
})
triggers_reload true
action [:create]
end
systemd_unit 'mastodon-delete-old-media-cache.timer' do
content({
Unit: {
Description: 'Delete old Mastodon media cache'
},
Timer: {
OnCalendar: '*-*-* 00:00:00',
Persistent: 'true'
},
Install: {
WantedBy: 'timer.target'
}
})
triggers_reload true
action [:create, :enable, :start]
end
firewall_rule "mastodon_app" do
port node['kosmos-mastodon']['app_port']
source "10.1.1.0/24"
protocol :tcp
command :allow
end
firewall_rule 'mastodon_streaming' do
port node['kosmos-mastodon']['streaming_port']
source "10.1.1.0/24"
protocol :tcp
command :allow
end
@@ -5,9 +5,10 @@
build_essential
version = "1.3.8"
version = "1.9.6"
venv = "/opt/libretranslate/venv"
%w{ python3 python3-pip python3-setuptools python3-dev }.each do |pkg|
%w{ python3 python3-pip python3-setuptools python3-dev python3-venv }.each do |pkg|
apt_package pkg
end
@@ -17,19 +18,26 @@ user "libretranslate" do
manage_home true
end
# LibreTranslate is installed into a dedicated virtualenv. Ubuntu 24.04's
# system Python is externally managed (PEP 668) and refuses `pip install`.
bash "create_libretranslate_venv" do
code "sudo -u libretranslate python3 -m venv #{venv}"
not_if { ::File.exist?("#{venv}/bin/pip") }
end
bash "install_libretranslate" do
code "sudo -u libretranslate pip3 install --user --prefer-binary libretranslate==#{version}"
code "sudo -u libretranslate #{venv}/bin/pip install --prefer-binary libretranslate==#{version}"
action :run
not_if { `sudo -u libretranslate pip3 list |grep libretranslate`.split(' ')[1] == version rescue false }
not_if "#{venv}/bin/pip show libretranslate 2>/dev/null | grep -q 'Version: #{version}'"
notifies :restart, "service[libretranslate]", :delayed
end
languages = `sudo -u libretranslate /opt/libretranslate/.local/bin/argospm search`
languages = `sudo -u libretranslate #{venv}/bin/argospm search`
languages.each_line do |line|
lang = line.split(':').first
bash "install_lt_#{lang}" do
code "sudo -u libretranslate /opt/libretranslate/.local/bin/argospm install #{lang}"
code "sudo -u libretranslate #{venv}/bin/argospm install #{lang}"
action :nothing
end
end
@@ -46,7 +54,7 @@ systemd_unit "libretranslate.service" do
User: "libretranslate",
Group: "libretranslate",
WorkingDirectory: "/opt/libretranslate/",
ExecStart: "/opt/libretranslate/.local/bin/libretranslate --host 127.0.0.1 --port 5000 --disable-files-translation",
ExecStart: "#{venv}/bin/libretranslate --host 127.0.0.1 --port 5000 --disable-files-translation",
Restart: "always"
},
Install: {
@@ -17,7 +17,6 @@ ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=<%= @active_record_encryption_key_d
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=<%= @active_record_encryption_primary_key %>
PAPERCLIP_SECRET=<%= @paperclip_secret %>
SECRET_KEY_BASE=<%= @secret_key_base %>
OTP_SECRET=<%= @otp_secret %>
# Registrations
# Single user mode will disable registrations and redirect frontpage to the first profile
@@ -74,6 +73,10 @@ AWS_SECRET_ACCESS_KEY=<%= @aws_secret_access_key %>
# locale
DEFAULT_LOCALE=<%= @default_locale %>
FORCE_DEFAULT_LOCALE=<%= @force_default_locale %>
# Email subscriptions (Mastodon 4.6+)
DISABLE_EMAIL_SUBSCRIPTIONS=<%= @disable_email_subscriptions %>
<% if @libre_translate_endpoint %>
# translate
@@ -1,7 +1,5 @@
[Unit]
Description=mastodon-sidekiq-scheduler
Requires=redis@6379.service
After=redis@6379.service
[Service]
Type=simple
@@ -1,7 +1,5 @@
[Unit]
Description=mastodon-sidekiq
Requires=redis@6379.service
After=redis@6379.service
[Service]
Type=simple
@@ -11,7 +9,7 @@ Environment="RAILS_ENV=production"
Environment="DB_POOL=<%= @sidekiq_threads %>"
Environment="MALLOC_ARENA_MAX=2"
Environment="LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2"
ExecStart=<%= @bundle_path %> exec sidekiq -c <%= @sidekiq_threads %> -q default -q mailers -q pull -q push -q ingress
ExecStart=<%= @bundle_path %> exec sidekiq -c <%= @sidekiq_threads %> -q default -q mailers -q pull -q push -q ingress -q fasp
TimeoutSec=15
Restart=always
@@ -1,7 +1,5 @@
[Unit]
Description=mastodon-web
Requires=redis@6379.service
After=redis@6379.service
[Service]
Type=simple
@@ -58,7 +58,9 @@ end
execute "bundle install" do
user deploy_user
cwd deploy_path
command "#{bundle_path} install --without development,test --deployment"
command "#{bundle_path} config set --local deployment true && " \
"#{bundle_path} config set --local without 'development test' && " \
"#{bundle_path} install"
end
template "#{deploy_path}/config.yml.erb" do