{"id":15019128,"url":"https://github.com/vedetta-com/caesonia","last_synced_at":"2025-04-04T14:06:05.230Z","repository":{"id":215851182,"uuid":"121041894","full_name":"vedetta-com/caesonia","owner":"vedetta-com","description":"OpenBSD Email Service","archived":false,"fork":false,"pushed_at":"2019-10-20T11:24:12.000Z","size":589,"stargazers_count":782,"open_issues_count":8,"forks_count":40,"subscribers_count":37,"default_branch":"master","last_synced_at":"2025-03-25T18:22:04.051Z","etag":null,"topics":["dovecot","gnupg","httpd","openbsd","rspamd","smtpd","unbound"],"latest_commit_sha":null,"homepage":null,"language":"Makefile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vedetta-com.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-02-10T18:24:08.000Z","updated_at":"2025-03-15T18:47:19.000Z","dependencies_parsed_at":"2024-01-07T01:44:33.115Z","dependency_job_id":"da1d7563-08ea-4e9a-bc05-70a5fece4e1d","html_url":"https://github.com/vedetta-com/caesonia","commit_stats":null,"previous_names":["vedetta-com/caesonia"],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vedetta-com%2Fcaesonia","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vedetta-com%2Fcaesonia/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vedetta-com%2Fcaesonia/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vedetta-com%2Fcaesonia/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vedetta-com","download_url":"https://codeload.github.com/vedetta-com/caesonia/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246963286,"owners_count":20861448,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dovecot","gnupg","httpd","openbsd","rspamd","smtpd","unbound"],"created_at":"2024-09-24T19:53:01.901Z","updated_at":"2025-04-04T14:06:05.210Z","avatar_url":"https://github.com/vedetta-com.png","language":"Makefile","funding_links":["https://opencollective.com/caesonia"],"categories":["Makefile","OpenBSD Provisioning"],"sub_categories":["Interviews with OpenBSD developers"],"readme":"# caesonia (beta)\n[![Backers on Open Collective](https://opencollective.com/caesonia/backers/badge.svg)](#backers)\n [![Sponsors on Open Collective](https://opencollective.com/caesonia/sponsors/badge.svg)](#sponsors) \n \n*Open*BSD Email Service\n\n![Public Domain](src/var/www/htdocs/mercury.example.com/Milonia_Caesonia-250x259.jpg)\n\n## About\n\u003e a free-email alternative\n\nRoot your Inbox :mailbox_with_mail:\n\n## Features\n- Efficient: configured to run on min. 512MB RAM and 20GB SSD, a KVM (cloud) VPS for around $2.50/mo\n- 15GB+ uncompressed Maildir, rivals top free-email providers (grow by upgrading SSD)\n- Email messages are gzip compressed, at least 1/3 more space with level 6 default\n- Server side full text search (headers and body) can be enabled (to use the extra space)\n- Mobile data friendly: IMAPS connections are compressed\n- Subaddress (+tag) support, to filter and monitor email addresses\n- Virtual domains, aliases, and credentials in files, Berkeley DB, or [SQLite3](https://github.com/OpenSMTPD/OpenSMTPD-extras/tree/master/extras/tables/table-sqlite)\n- Naive Bayes rspamd filtering with supervised learning: the lowest false positive spam detection rates\n- Carefree automated Spam/ and Trash/ cleaning service (default: older than 30 days)\n- Automated quota management, gently assists when over quota\n- Easy backup MX setup: using the same configuration, install in minutes on a different host\n- Worry-free automated master/master replication with backup MX, prevents accidental loss of email messages\n- Resilient: the backup MX can be used as primary, even when the primary is not down, both perfect replicas\n- Flexible: switching roles is easy, making the process of changing VPS hosts a breeze (no downtime)\n- DMARC (with DKIM and SPF) email-validation system, to detect and prevent email spoofing\n- Uncensored DNS validating resolver from root nameservers\n- OpenPGP Web Key Service with Web Key Directory, automatic key exchange protocol\n- MUA Autoconfiguration, for modern clients\n- Daily (spartan) stats, to keep track of things\n- Your sieve scripts and managesieve configuration, let's get started\n\n## Considerations\nBy design, email message headers need to be public, for exchanges to happen. The body of the message can be [encrypted](INSTALL.md#openpgp-web-key-service-wks) by the user, if desired. Moreover, there is no way to prevent the host from having access to the virtual machine. Therefore, [full disk encryption](https://www.openbsd.org/faq/faq14.html#softraidFDE) (at rest) may not be necessary.\n\nGiven our low memory requirements, and the single-purpose concept of email service, Roundcube or other web-based IMAP email clients should be on a different VPS.\n\nAntivirus software users (usually) have the service running on their devices. ClamAV can easily be incorporated into this configuration, if affected by the [types of malware](https://www.shadowserver.org/wiki/pmwiki.php/AV/Virus180-DayStats) it protects against, but will require around 1GB additional RAM (or another VPS).\n\nEvery email message is important, if properly delivered, for Bayes classification. At least 200 ham and 200 spam messages are required to learn what one considers junk (2000+ for best results). By default (change to use case), a rspamd score above 50% will send the message to Spam/. Moving messages in and out of Spam/ changes this score. After 95%, the message is flagged as \"seen\" and can be safely ignored.\n\n[spamd](https://man.openbsd.org/spamd) is effective at greylisting and stopping high volume spam, if it becomes a problem. It will be an option when IPv6 is supported, along with [bgp-spamd](https://bgp-spamd.net/). To build IP lists for greylisting, please use [spfwalk](https://github.com/akpoff/spfwalk) with [spf_fetch](https://github.com/akpoff/spf_fetch).\n\nSystem mail is delivered to an alias mapped to a virtual user served by the service. This way, messages are guaranteed to be delivered via encrypted connection. It is not possible for real users to alias, nor `mail` an external mail address with the default configuration.\ne.g. puffy@mercury.example.com is wheel, with an alias mapped to (virtual) puffy@example.com, and user (puffy) can be different for each.\n\n## Getting started\n\nSee [**Prerequisites**](#prerequisites) and the [**Installation Guide**](INSTALL.md) for details.\n\nGrab a copy of this repository, and put overrides in \"[Makefile](Makefile).local\" e.g.:\n```console\n# Makefile.local\n\nDOMAIN_NAME =   example.com\nVHOSTS_NAME =   example.net \\\n                example.org\n\nPRIMARY =       yes\n\nPRIMARY_HOST =\tmercury\nPRIMARY_IPv4 =\t203.0.113.1\nPRIMARY_IPv6 =\t2001:0db8::1\n\nBACKUP_HOST =\thermes\nBACKUP_IPv4 =\t203.0.113.2\nBACKUP_IPv6 =\t2001:0db8::2\n\nDKIM_SELECTOR =\tobsd\nEGRESS =\tvio0\n\nWHEEL_USER =\tpuffy\nREPLICATION_USER =\tdsync\nVIRTUAL_USER =\t${WHEEL_USER}\n\nAUTOEXPUNGE =\t30d\nMAIL_QUOTA =\t15G\nMAX_MESSAGE_SIZE =\t35M\nFULL_SYNC_INTERVAL =\t1h\n\nUPGRADE =\tyes\n```\n\n#### Install\n```console\nmake install\n```\n\n*n.b.* UPGRADE uses [`sdiff`](https://man.openbsd.org/sdiff) side-by-side diff (with *new* on the right side)\n\n#### Virtual Users\nUpdate virtual users [credentials table](https://man.openbsd.org/table.5#Credentials_tables) [`src/etc/mail/passwd`](src/etc/mail/passwd) using [`smtpctl encrypt`](https://man.openbsd.org/smtpctl#encrypt)\n```console\nsmtpctl encrypt\n\u003e secret\n\u003e $2b$...encrypted...passphrase...\nvi src/etc/mail/passwd\n\u003e puffy@example.com:$2b$...encrypted...passphrase...::::::\nsmtpctl update table passwd\n```\n\n*n.b.*: user [quota](src/etc/dovecot/conf.d/90-quota.conf) limit can be [overriden](src/etc/dovecot/conf.d/auth-passwdfile.conf.ext) from [src/etc/mail/passwd](src/etc/mail/passwd)\n```console\npuffy@example.com:$2b$...encrypted...passphrase...::::::userdb_quota_rule=*:storage=7G\n```\n\nReview [virtual domains](https://man.openbsd.org/makemap#VIRTUAL_DOMAINS) [aliasing table](https://man.openbsd.org/table.5#Aliasing_tables) [`src/etc/mail/virtual`](src/etc/mail/virtual)\n\n*n.b.* see [Administration](https://github.com/vedetta-com/caesonia/blob/master/INSTALL.md#administration) for virtual user and domain management\n\n#### Backup MX\n*n.b.* Without backup MX, leave BACKUP_HOST empty in \"Makefile.local\"\n\nDovecot Replication user \"dsync\" [SSH](src/etc/ssh/sshd_config) limited to one \"[command](src/home/dsync/.ssh/authorized_keys)\" restricted in [`doas.conf`](src/etc/doas.conf) to match \"[dsync_remote_cmd](src/etc/dovecot/conf.d/90-replication.conf.optional)\". On primary and backup hosts\n\n```console\nsu - dsync\nssh-keygen\necho \"command=\\\"doas -u vmail \\${SSH_ORIGINAL_COMMAND#*}\\\" $(cat ~/.ssh/id_rsa.pub)\" | \\\n\tssh puffy@hermes.example.com \"cat \u003e\u003e /home/dsync/.ssh/authorized_keys\"\nexit\n```\n\nAlternatively, [OpenSSH certificates](https://github.com/vedetta-com/vedetta/blob/master/src/usr/local/share/doc/vedetta/OpenSSH_Principals.md) allow fine-grained control to local users and hosts. The `force-command` is passed to ssh-keygen as certificate option (-O) instead of using \"authorized_keys\".\n\nUpdate [/home/dsync](src/home/dsync), on primary and backup hosts\n```console\nchown -R root:dsync /home/dsync\nchmod 750 /home/dsync/.ssh\nchmod 640 /home/dsync/.ssh/{authorized_keys,id_*.pub,known_hosts}\nchmod 400 /home/dsync/.ssh/{id_ecdsa,id_ed25519,id_rsa}\nchown dsync /home/dsync/.ssh/{id_ecdsa,id_ed25519,id_rsa}\n```\n\nUpdate [`/root/.ssh/known_hosts`](src/root/.ssh/known_hosts) on primary and backup hosts\n```console\nssh -4 -i/home/dsync/.ssh/id_rsa -ldsync hermes.example.com \"exit\"\nssh -6 -i/home/dsync/.ssh/id_rsa -ldsync hermes.example.com \"exit\"\n```\n\n#### Client Configuration\n*n.b.*: MUA auto-configuration via [Autoconfiguration](README.md#mozilla-autoconfiguration) and SRV Records for\n [Locating Email Services](README.md#srv-records-for-locating-email-services)\n\n- IMAP server: mercury.example.com (or hermes.example.com)\n  - Security: TLS\n  - Port: 993\n  - Username: puffy@example.com\n  - Password: ********\n  - Autodetect IMAP namespace :ballot_box_with_check:\n  - Use compression :ballot_box_with_check:\n  - Poll when connecting for push :ballot_box_with_check:\n\n- SMTP server: mercury.example.com (or hermes.example.com)\n  - Security: TLS\n  - Port: 465\n  - Require sign-in :ballot_box_with_check:\n  - Username: puffy@example.com\n  - Authentication: Normal password\n  - Password: ********\n\n- SMTP server: mercury.example.com (or hermes.example.com)\n  - Security: STARTTLS\n  - Port: 587\n  - Require sign-in :ballot_box_with_check:\n  - Username: puffy@example.com\n  - Authentication: Normal password\n  - Password: ********\n\n## Prerequisites\nA DNS name server (from a registrar, a free service, VPS host, or [self-hosted](https://github.com/vedetta-com/dithematic)) is required, which allows editing the following record types: [A](#forward-confirmed-reverse-dns-fcrdns), [AAAA](#forward-confirmed-reverse-dns-fcrdns), [MX](#mail-exchanger-mx), [CNAME](#mozilla-autoconfiguration), [SRV](#srv-records-for-locating-email-services), [CAA](#certification-authority-authorization-caa), [SSHFP](#secure-shell-fingerprint-sshfp), [TXT](#sender-policy-framework-spf)\n\n*n.b.* see [example zone](https://github.com/vedetta-com/dithematic/blob/master/src/usr/local/share/examples/dithematic/example.com.zone)\n\n**DNSSEC is [recommended](https://www.icann.org/news/announcement-2019-02-22-en)**\n\n#### Forward-confirmed reverse DNS ([FCrDNS](https://tools.ietf.org/html/draft-ietf-dnsop-reverse-mapping-considerations-06))\nPrimary domain has record types A, and AAAA for each MX subdomain with the relays' IPv4, and IPv6\n```console\nmercury.example.com\t86400\tIN\tA\t203.0.113.1\nmercury.example.com\t86400\tIN\tAAAA\t2001:0db8::1\n```\nEach IPv4 and IPv6 has record type PTR with the MX subdomain (reverse DNS configured on VPS host)\n```console\n...6\t\t\t\tIN\tPTR \tmercury.example.com\n```\nVerify:\n```sh\ndig +short mercury.example.com a\n\u003e 203.0.113.1\ndig +short -x 203.0.113.1\n\u003e mercury.example.com.\n\ndig +short mercury.example.com aaaa\n\u003e 2001:0db8::1\ndig +short -x 2001:0db8::1\n\u003e mercury.example.com.\n```\n\n#### Mail eXchanger ([MX](https://tools.ietf.org/html/rfc5321))\nPrimary and *virtual* domains have identical records type MX with priority and relay hostnames\n```console\nexample.com\t86400\tIN\tMX\t10 mercury.example.com\nexample.com\t86400\tIN\tMX\t20 hermes.example.com\n```\n\n#### Mozilla [Autoconfiguration](https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Autoconfiguration)\nPrimary and *virtual* domains have identical records type CNAME for *autoconfig* subdomain pointing to Autoconfiguration server\n```console\nautoconfig.example.com\t86400\tIN\tCNAME\tmercury.example.com\n```\n\n#### OpenPGP Web Key Directory ([WKD](https://tools.ietf.org/html/draft-koch-openpgp-webkey-service-08))\nPrimary and *virtual* domains have identical records type CNAME for *wkd* subdomain pointing to Web Key Server\n```console\nwkd.example.com\t\t86400\tIN\tCNAME\tmercury.example.com\n```\n\n#### SRV Records for OpenPGP [Web Key Directory](https://wiki.gnupg.org/WKD)\nPrimary domain has record type SRV with primary WKD subdomain\n```console\n_openpgpkey._tcp.example.com\t86400\tIN\tSRV\t0 0 443\twkd.example.com\n```\n\nEach *virtual* domain has record type SRV with *virtual* WKD subdomain\n```console\n_openpgpkey._tcp.example.net\t86400\tIN\tSRV\t0 0 443\twkd.example.net\n```\n\n#### SRV Records for [Locating Email Services](https://tools.ietf.org/html/rfc6186)\nPrimary and *virtual* domains have identical records type SRV for simple MUA auto-configuration\n```console\n_submission._tcp.example.com\t86400\tIN\tSRV\t0 1 465 mercury.example.com\n_submission._tcp.example.com\t86400\tIN\tSRV\t5 1 587\tmercury.example.com\n_imaps._tcp.example.com\t\t86400\tIN\tSRV\t0 1 993\tmercury.example.com\n_imap._tcp.example.com\t\t86400\tIN\tSRV\t0 0 0   .\n_pop3s._tcp.example.com\t\t86400\tIN\tSRV\t0 0 0   .\n_pop3._tcp.example.com\t\t86400\tIN\tSRV\t0 0 0\t.\n```\n\n#### Certification Authority Authorization ([CAA](https://tools.ietf.org/html/rfc6844))\nPrimary and *virtual* domains have identical records type CAA with *[letsencrypt.org](https://letsencrypt.org/)* as the only CA allowed to issue certificates\n```console\nexample.com\t86400\tIN\tCAA\t128 issue \"letsencrypt.org\"\nexample.com\t86400\tIN\tCAA\t128 issuewild \";\"\n```\n\n#### Secure Shell Fingerprint ([SSHFP](https://man.openbsd.org/ssh#VERIFYING_HOST_KEYS))\nPrint the SSHFP fingerprint resource record on each hostname\n```sh\nssh-keygen -r mercury.example.com\n```\n\nPrimary domain has records type SSHFP for each MX subdomain with a fingerprint of the server's public key\n```console\nmercury.example.com\t86400\tIN\tSSHFP\t1 1 2...\nmercury.example.com\t86400\tIN\tSSHFP\t1 2 5...\nmercury.example.com\t86400\tIN\tSSHFP\t3 1 6...\nmercury.example.com\t86400\tIN\tSSHFP\t3 2 8...\nmercury.example.com\t86400\tIN\tSSHFP\t4 1 7...\nmercury.example.com\t86400\tIN\tSSHFP\t4 2 a...\n```\n\n#### Sender Policy Framework ([SPF](https://tools.ietf.org/html/rfc7208))\nPrimary and *virtual* domains have identical records type TXT with primary domain SPF data\n```console\nexample.com\t\t86400\tIN\tTXT\t\"v=spf1 mx:example.com -all\"\n```\n\nPrimary domain has record type TXT for each MX subdomain, to return receipt notifications (DSNs and MDNs), with relays' IP SPF data\n```console\nmercury.example.com\t86400\tIN\tTXT\t\"v=spf1 a -all\"\nhermes.example.com\t86400\tIN\tTXT\t\"v=spf1 a -all\"\n```\n\n#### Domain Keys Identified Mail ([DKIM](http://www.dkim.org))\nGenerate a private and public key\n```sh\nmkdir -p /etc/ssl/dkim/private\nchmod 750 /etc/ssl/dkim/private\n```\n\u003e Signers SHOULD use RSA keys of at least 2048 bits. -- https://tools.ietf.org/html/rfc8301#section-3.2\n\n```sh\n(umask 337; openssl genrsa -out /etc/ssl/dkim/private/private.key 2048)\nopenssl rsa -in /etc/ssl/dkim/private/private.key -pubout -out /etc/ssl/dkim/public.key\nchown -R _rspamd:_dkimproxy /etc/ssl/dkim/private\n```\n\n\u003e Widely used DNS configuration software places a practical limit on key sizes, because the software only handles a single 256-octet string in a TXT record, and RSA keys significantly longer than 1024 bits don't fit in 256 octets. -- https://tools.ietf.org/html/rfc8301#section-1\n\n\u003e Multiple strings in a single DNS record are useful in constructing records that would exceed the 255-byte maximum length of a string within a single TXT RR record. -- https://tools.ietf.org/html/rfc4408#section-3.1.3\n\nGenerate the TXT-DATA field for DKIM TXT record\n```sh\necho \"v=DKIM1; k=rsa; p=$(sed -e '1d' -e '$d' /etc/ssl/dkim/public.key | tr -d '\\n')\"\n```\n\nAlternatively\n```sh\n(umask 337; rspamadm dkim_keygen -d example.com -s 'obsd' -k /etc/ssl/dkim/private/private.key -b 2048 -t rsa) \u003e /etc/ssl/dkim/public.key\n```\n\nPrimary and *virtual* domains have identical records type TXT for *selector._domainkey* subdomain with DKIM public key\n```console\nobsd._domainkey.example.com\t86400\tIN\tTXT\t( \"v=DKIM1; k=rsa; \"\n\t\"p=abcd\"\n\t\"ef\"\n) ;\n```\n\n#### Domain-based Message Authentication, Reporting \u0026 Conformance ([DMARC](https://dmarc.org/))\nPrimary and *virtual* domains have record type TXT for *_dmarc* subdomain with DMARC policy data\n```console\n_dmarc.example.com\t86400\tIN\tTXT\t\"v=DMARC1; p=reject; pct=100; rua=mailto:dmarcreports@example.com\"\n```\n\n#### SMTP MTA Strict Transport Security ([MTA-STS](https://tools.ietf.org/html/rfc8461))\nPrimary domain has record type TXT for *_mta-sts* subdomain with MTA-STS reporting data\n```console\n_mta-sts.example.com\t86400\tIN\tTXT\t\"v=STSv1; id=20190515085700Z;\"\n```\n\nEach *virtual* domain has record type CNAME for *_mta-sts* subdomain pointing to MTA-STS TXT record\n```console\n_mta-sts.example.net\t86400\tIN\tCNAME\t_mta-sts.example.com\n```\n\nPrimary and *virtual* domains have identical records type CNAME for *mta-sts* subdomain pointing to MTA-STS policy\n```console\nmta-sts.example.com\t86400\tIN\tCNAME\tmercury.example.com\n```\n\n#### SMTP TLS Reporting ([SMTP TLSRPT](https://tools.ietf.org/html/rfc8460))\nPrimary and *virtual* domains have records type TXT for *_smtp._tls* subdomain with TLS reporting data\n```console\n_smtp._tls.example.com\t86400\tIN\tTXT\t\"v=TLSRPTv1;rua=mailto:tlsreports@example.com\"\n```\n\n#### SMTP Security via Opportunistic DNS-Based Authentication of Named Entities ([DANE](https://tools.ietf.org/html/rfc7671)) Transport Layer Security ([TLS](https://tools.ietf.org/html/rfc7672))\n**requires DNSSEC** and manual server key rotation using the procedure form rfc7671\n\nPrint each relay's TLSA resource record\n```sh\npkg_add ldns-utils\nldns-dane create mercury.example.com 443 3 1 1\nldns-dane create hermes.example.com 443 3 1 1\n```\n\nPrimary domain has records type TLSA for each *tlsa._dane* MX subdomain\n```console\ntlsa._dane.mercury.example.com\t86400\tIN\tTLSA\t3 1 1 e3b0c44298fc1c14...\ntlsa._dane.hermes.example.com\t86400\tIN\tTLSA\t3 1 1 f2c0d55309cf2d25...\n```\n\nPrimary domain has records type CNAME for each *_service._tcp* MX subdomain pointing to TLSA RR\n```console\n_993._tcp.mercury.example.com\t86400\tIN\tCNAME\ttlsa._dane.mercury.example.com\n_587._tcp.mercury.example.com\t86400\tIN\tCNAME\ttlsa._dane.mercury.example.com\n_443._tcp.mercury.example.com\t86400\tIN\tCNAME\ttlsa._dane.mercury.example.com\n_25._tcp.mercury.example.com\t86400\tIN\tCNAME\ttlsa._dane.mercury.example.com\n\n_993._tcp.hermes.example.com\t86400\tIN\tCNAME\ttlsa._dane.hermes.example.com\n_587._tcp.hermes.example.com\t86400\tIN\tCNAME\ttlsa._dane.hermes.example.com\n_443._tcp.hermes.example.com\t86400\tIN\tCNAME\ttlsa._dane.hermes.example.com\n_25._tcp.hermes.example.com\t86400\tIN\tCNAME\ttlsa._dane.hermes.example.com\n```\n\n## Support\n[Issues](https://github.com/vedetta-com/caesonia/issues)\n\n## Social\n[#caesonia:matrix.org](https://riot.im/app/#/room/#caesonia:matrix.org) (deadish)\n\n[#caesonia@bsd.network](https://bsd.network/tags/caesonia)\n\n## Contribute\nContributions welcome, [fork](https://github.com/vedetta-com/caesonia/fork)\n\nHosted by Open Source Collective 501c6, [contribute](https://opencollective.com/caesonia)\n\n\n## Contributors\n\nThis project exists thanks to all the people who contribute. \n\u003ca href=\"https://github.com/vedetta-com/caesonia/graphs/contributors\"\u003e\u003cimg src=\"https://opencollective.com/caesonia/contributors.svg?width=890\u0026button=false\" /\u003e\u003c/a\u003e\n\n\n## Backers\n\nThank you to all our backers! :pray: [[Become a backer](https://opencollective.com/caesonia#backer)]\n\n\u003ca href=\"https://opencollective.com/caesonia#backers\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/caesonia/backers.svg?width=890\"\u003e\u003c/a\u003e\n\n\n## Sponsors\n\nSupport this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/caesonia#sponsor)]\n\n\u003ca href=\"https://opencollective.com/caesonia/sponsor/0/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/caesonia/sponsor/0/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/caesonia/sponsor/1/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/caesonia/sponsor/1/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/caesonia/sponsor/2/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/caesonia/sponsor/2/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/caesonia/sponsor/3/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/caesonia/sponsor/3/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/caesonia/sponsor/4/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/caesonia/sponsor/4/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/caesonia/sponsor/5/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/caesonia/sponsor/5/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/caesonia/sponsor/6/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/caesonia/sponsor/6/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/caesonia/sponsor/7/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/caesonia/sponsor/7/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/caesonia/sponsor/8/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/caesonia/sponsor/8/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/caesonia/sponsor/9/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/caesonia/sponsor/9/avatar.svg\"\u003e\u003c/a\u003e\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvedetta-com%2Fcaesonia","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvedetta-com%2Fcaesonia","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvedetta-com%2Fcaesonia/lists"}