Compare commits

..

26 commits

Author SHA1 Message Date
804c311b02 Merge branch 'stage' into prod
All checks were successful
/ build (push) Successful in 35s
2025-12-27 15:31:15 +01:00
137565ca70 ffs
All checks were successful
/ build (push) Successful in 41s
2025-12-27 13:41:26 +01:00
dd668438fa ci ffs
All checks were successful
/ build (push) Successful in 35s
2025-12-27 02:26:36 +01:00
867361c3cc ci ffs
All checks were successful
/ build (push) Successful in 37s
2025-12-27 01:58:27 +01:00
f0fe64980f remove github build stuff because I build on forgejo 2025-12-27 01:38:02 +01:00
b3a3a2f8eb npm update
All checks were successful
/ build (push) Successful in 47s
2025-12-27 01:33:58 +01:00
47422745b4 removed remains of matomo
All checks were successful
/ build (push) Successful in 55s
2025-12-27 01:23:11 +01:00
32031e05f2 fixed code block 2025-12-27 01:22:59 +01:00
7e2abb2e1f replaced matomo by rybbit 2025-12-27 01:22:49 +01:00
28431dbef9 ffs
All checks were successful
/ build (push) Successful in 50s
2025-12-27 00:52:20 +01:00
395a187b36 try caching the NPM packages
All checks were successful
/ build (push) Successful in 1m40s
2025-12-27 00:49:55 +01:00
5c452cb495 add missing information about managesieve plugin
All checks were successful
/ build (push) Successful in 1m17s
2025-12-27 00:04:02 +01:00
66990a037e ffs
All checks were successful
/ build (push) Successful in 50s
2025-12-20 23:22:39 +01:00
81d1807d4f ffs
Some checks failed
/ build (push) Failing after 50s
2025-12-20 22:04:30 +01:00
66da5c414e ffs
Some checks failed
/ build (push) Failing after 56s
2025-12-20 22:01:01 +01:00
5f7a8365d2 ffs
Some checks failed
/ build (push) Failing after 48s
2025-12-20 21:55:30 +01:00
c81d9fcba2 ffs
Some checks failed
/ build (push) Failing after 55s
2025-12-20 21:51:14 +01:00
3e2d69daea ffs
Some checks failed
/ build (push) Failing after 1m0s
2025-12-20 21:49:18 +01:00
decbf1cc8c ffs
Some checks failed
/ build (push) Failing after 1m12s
2025-12-20 21:45:53 +01:00
a63a724457 ffs
All checks were successful
/ build (push) Successful in 1m15s
2025-12-20 21:10:15 +01:00
61d080e34b ffs
All checks were successful
/ build (push) Successful in 41s
2025-12-20 21:09:12 +01:00
1abedb6c2d ffs
All checks were successful
/ build (push) Successful in 3s
2025-12-20 21:08:30 +01:00
bb1ce601be ffs
Some checks failed
/ build (push) Failing after 0s
2025-12-20 20:59:54 +01:00
24c5e5b418 Merge branch 'dev' into stage
Some checks failed
/ build (push) Failing after 0s
2025-12-20 20:56:36 +01:00
1d63ab69af ffs 2025-12-20 20:56:26 +01:00
b947ea0748 testing the forgejo runners
All checks were successful
/ print-content (push) Successful in 47s
2025-12-17 21:03:01 +01:00
9 changed files with 984 additions and 789 deletions

View file

@ -0,0 +1,63 @@
on:
push:
branches:
- stage
- prod
jobs:
build:
runs-on: docker
#environment: ${{ env.FORGEJO_REF_NAME }}
container:
image: node:22
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Cache node modules
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm ci
- name: Build Astro project
run: npm run build
- name: Deploy dist to dist-${{ env.FORGEJO_REF_NAME }}
run: |
git config user.name "forgejo-actions[bot]"
git config user.email "forgejo-actions[bot]@users.noreply.local"
git checkout --orphan temp
git rm -rf .
git add dist
git commit -m "Update dist for ${{ env.FORGEJO_REF_NAME }}"
git push \
"https://x-access-token:${{ secrets.FORGEJO_TOKEN }}@git.workaround.org/${{ github.repository }}.git" \
temp:dist-${{ env.FORGEJO_REF_NAME }} \
--force
- name: Trigger deployment webhook
env:
DEPLOY_WEBHOOK: ${{ secrets.COOLIFY_DEPLOY_WEBHOOK }}
DEPLOY_TOKEN: ${{ secrets.COOLIFY_DEPLOY_TOKEN }}
run: |
if [ "${{ env.FORGEJO_REF_NAME }}" = "stage" ]; then
DEPLOY_WEBHOOK="${{ secrets.COOLIFY_DEPLOY_WEBHOOK_STAGE }}"
DEPLOY_TOKEN="${{ secrets.COOLIFY_DEPLOY_TOKEN_STAGE }}"
else
DEPLOY_WEBHOOK="${{ secrets.COOLIFY_DEPLOY_WEBHOOK_PROD }}"
DEPLOY_TOKEN="${{ secrets.COOLIFY_DEPLOY_TOKEN_PROD }}"
fi
curl -v "$DEPLOY_WEBHOOK" \
--header "Authorization: Bearer $DEPLOY_TOKEN"

View file

@ -1,58 +0,0 @@
name: Build Astro and deploy dist
on:
push:
branches:
- stage
- prod
workflow_dispatch:
permissions:
contents: write # 👈 This is required for pushing branches
jobs:
build:
runs-on: ubuntu-latest
# Dynamically set environment name based on branch
environment: ${{ github.ref_name }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22" # match your project
- name: Install dependencies
run: npm ci
- name: Build Astro project
run: npm run build
- name: Deploy dist to dist-${{ github.ref_name }}
run: |
# Configure Git
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Create temporary branch
git checkout --orphan temp-build
# Clean it
git rm -rf .
# Commit and force push
git add dist
git branch
git commit -m "Update dist/ [skip ci]"
git push https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }} temp-build:dist-${{ github.ref_name }} --force
- name: Trigger deployment webhook
run: |
curl -v "$DEPLOY_WEBHOOK" --header "Authorization: Bearer $DEPLOY_TOKEN"
env:
DEPLOY_WEBHOOK: ${{ secrets.COOLIFY_DEPLOY_WEBHOOK }}
DEPLOY_TOKEN: ${{ secrets.COOLIFY_DEPLOY_TOKEN }}

View file

@ -2,7 +2,6 @@
import { defineConfig } from "astro/config";
import starlight from "@astrojs/starlight";
import sitemap from "@astrojs/sitemap";
import matomo from "astro-matomo";
import remarkSmartypants from "remark-smartypants";
// https://astro.build/config
@ -72,18 +71,6 @@ export default defineConfig({
replacesTitle: true,
},
}),
// https://github.com/felix-berlin/astro-matomo
// matomo({
// enabled: import.meta.env.PROD, // Only load in production
// host: "https://matomo.workaround.org/",
// setCookieDomain: "*.workaround.org",
// trackerUrl: "js/", // defaults to matomo.php
// srcUrl: "js/", // defaults to matomo.js
// siteId: 1,
// heartBeatTimer: 5,
// disableCookies: true,
// debug: false,
// }),
sitemap(),
],

1528
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,6 @@
"@astrojs/starlight": "^0.35.2",
"@splidejs/splide": "^4.1.4",
"astro": "^5.13.2",
"astro-matomo": "^1.9.0",
"astro-splide": "^2.0.0",
"sharp": "^0.32.6",
"typescript": "^5.9.2"

View file

@ -7,13 +7,18 @@ sidebar:
## Can I use this guide for my own work?
Previously I claimed a copyright on the documentation. However lets make things simpler. This Bullseye guide is using the [Creative Commons BY-NC-SA license](https://creativecommons.org/licenses/by-nc-sa/4.0/). Which means:
Previously I claimed a copyright on the documentation. However lets make things simpler. This Bullseye guide is using
the [Creative Commons BY-NC-SA license](https://creativecommons.org/licenses/by-nc-sa/4.0/). Which means:
- BY = Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
- NC = NonCommercial — You may not use the material for commercial purposes. Do what you want with your mail server. But lets keep the knowledge free.
- SA = ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
- BY = Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made.
You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
- NC = NonCommercial — You may not use the material for commercial purposes. Do what you want with your mail server. But
lets keep the knowledge free.
- SA = ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under
the same license as the original.
Besides that this guide has been a team effort. Many readers have contributed to it. I may spend the time to turn it into a guide but a lot of good ideas were not mine alone.
Besides that this guide has been a team effort. Many readers have contributed to it. I may spend the time to turn it
into a guide but a lot of good ideas were not mine alone.
## Can I advertise in your guide?
@ -21,33 +26,47 @@ No. There is no financial motivation. I just strive for freeing the world of ema
## Why dont you use Nginx/PostgreSQL?
I personally prefer that software, too. Just go for it. But for the sake of consistency lets keep Apache and MySQL as default choices in this guide so that readers upgrading from previous versions dont have to switch.
I personally prefer that software, too. Just go for it. But for the sake of consistency lets keep Apache and MySQL as
default choices in this guide so that readers upgrading from previous versions dont have to switch.
## Do you offer paid support?
Generally, yes. Aside from my day job, I am a sysadmin freelancer. If you are just stuck at some point you may want to ask in the [chat](https://riot.im/app/#/room/#ispmail:matrix.org) first though. You can find me there as well.
Generally, yes. Aside from my day job, I am a sysadmin freelancer. If you are just stuck at some point you may want to
ask in the [chat](https://riot.im/app/#/room/#ispmail:matrix.org) first though. You can find me there as well.
## How do I filter out malware?
I understand the need for it. If your users are using low-security operating systems (e.g. those that run EXE files) they are threatened by a lot of security problems. From the perspective of an email provider I would not want to take responsibility for filtering emails. That is only working on symptoms and not addressing the actual issues. Security is a fundamental concept and not something you slap on top of something inherently broken. I would not want to be blamed for a crypto trojan infection because the user relied on me saving them from bad things to happen. Client security in non-free systems is a topic on its own.
I understand the need for it. If your users are using low-security operating systems (e.g. those that run EXE files)
they are threatened by a lot of security problems. From the perspective of an email provider I would not want to take
responsibility for filtering emails. That is only working on symptoms and not addressing the actual issues. Security is
a fundamental concept and not something you slap on top of something inherently broken. I would not want to be blamed
for a crypto trojan infection because the user relied on me saving them from bad things to happen. Client security in
non-free systems is a topic on its own.
## Debian packages are too old and insecure
If you use a Debian stable release you have chosen to stay on a specific software version. “Stable” means “a version that will not change”. Thats the best choice for a server. Those software packages are by no means less secure though because they also get security updates. Debian also has up-to-date packages but you surely dont want to use them for a mail server unless you feel adventurous or have an intense hatred for your users. For a detailed discussion see [this separate article](https://workaround.org/debian-packages-are-so-old/).
If you use a Debian stable release you have chosen to stay on a specific software version. “Stable” means “a version
that will not change”. Thats the best choice for a server. Those software packages are by no means less secure though
because they also get security updates. Debian also has up-to-date packages but you surely dont want to use them for a
mail server unless you feel adventurous or have an intense hatred for your users. For a detailed discussion see
[this separate article](https://workaround.org/debian-packages-are-so-old/).
## Can I download the guide as one file?
Unfortunately there is no easy way to accomplish that. Especially with interactive components like tabs of quizzes. The reasons are technical not malice.
Unfortunately there is no easy way to accomplish that. Especially with interactive components like tabs of quizzes. The
reasons are technical not malice.
## Your guide looks cool. How did you make it?
The site is generated using [Starlight](https://starlight.astro.build/). Discussions at the bottom of each page are powered by [Comentario](https://comentario.app/).
Diagrams have been created using [Inkscape](https://inkscape.org/). User tracking is handled by [Matomo](https://matomo.org/).
The site is generated using [Starlight](https://starlight.astro.build/). Discussions at the bottom of each page are
powered by a self-hosted instance of [Comentario](https://comentario.app/). Diagrams have been created using
[Inkscape](https://inkscape.org/). User tracking is handled by a self-hosted instance of [Rybbit](https://rybbit.com/).
Everything here has been generated using open-source software and is not using any public cloud services.
## I can offer to translate your guide.
That is very kind to offer help. I understand the motivation to give back something. But trust me: you will lose interest quickly and regret your offer.
The guide is huge. It may not appear like much but once you start typing you realize just how many months of work went into it.
Even translating will take 1-2 weeks of your time. And after that someone would have to maintain both the original version and your translation.
We tried that a couple of times and it did not turn out well.
That is very kind to offer help. I understand the motivation to give back something. But trust me: you will lose
interest quickly and regret your offer. The guide is huge. It may not appear like much but once you start typing you
realize just how many months of work went into it. Even translating will take 1-2 weeks of your time. And after that
someone would have to maintain both the original version and your translation. We tried that a couple of times and it
did not turn out well.

View file

@ -126,10 +126,18 @@ email address as the user name. E.g. `john@example.org` and password `summersun`
If the login fails, check `/var/log/roundcube/errors.log`.
<Aside type="tip" title="Important">
Before you get overly enthusiastic: you can't send emails from Roundcube yet. We will fix that now.
</Aside>
## Plugins
Roundcube comes with various plugins that you can offer your users. I suggest that you enable at least the **password**
plugin so that your users can change their access password.
Roundcube comes with various plugins that you can offer your users. I suggest that you enable at least
- the **password** plugin so that your users can change their access password
- the **managesieve** plugin so that your users can create server-based filtering rules
Again edit the `/etc/roundcube/config.inc.php` file and look for the _plugins_ configuration. To enable the recommended
plugins change it to:
@ -141,8 +149,11 @@ $config['plugins'] = array(
);
```
Plugins are configured through files located in the `/etc/roundcube/plugins` directory. Let's quickly set up the
password plugin:
Plugins are configured through files located in the `/etc/roundcube/plugins` directory.
### password
Let's quickly set up the password plugin:
```sh title="Run this on your server"
cat > /etc/roundcube/plugins/password/config.inc.php << 'EOF'
@ -161,7 +172,7 @@ chown root:www-data /etc/roundcube/plugins/password/config.inc.php
chmod u=rw,g=r,o= /etc/roundcube/plugins/password/config.inc.php
```
Lets briefly cover the meaning of those lines:
What these settings mean:
- `$config['password_driver'] = 'sql';`\
Use SQL as a backend.
@ -191,8 +202,32 @@ Try it. Log into Roundcube as `john@example.org` with password summersun.
Enter a new password twice. You should get a success message at the bottom right. Now logout and login with the new
password. Does it work? Great.
<Aside type="tip" title="Important">
### managesieve
Before you get overly enthusiastic: you can't send emails from Roundcube yet. We will fix that now.
[Sieve](<https://en.wikipedia.org/wiki/Sieve_(mail_filtering_language)>) is a simple programming language to be used for
server-side rules. Dovecot executes these rules every time a new email comes in. There are global rules that are
executed for every email. And of course every user/mailbox can have its own rules. To manage sieve rules Dovecot offers
the _managesieve_ interface that you enabled earlier. So we just need to tell Roundcube how to access it.
</Aside>
The configuration file for Roundcubes _managesieve_ plugin is found at
`/etc/roundcube/plugins/managesieve/config.inc.php`. But the defaults are fine so you do not need to change it.
Sieve rules are stored in a special syntax on the server. This is an example that moves all incoming emails to the
_test_ folder that have “test” in the subject:
```
require ["fileinto"];
if header :contains "subject" "test"
{
fileinto "INBOX/test";
}
```
You do not need to learn this syntax though. Roundcubes sieve rule editor is way more user-friendly.
Try adding a sieve rule for `john@example.org` in Roundcube. That feature is located in Settings/Filters. You will find
the machine-readable sieve code at `/var/vmail/example.org/john/sieve/roundcube.sieve`.
The rule editor looks like this:
![Roundcube's sieve rule editor](images/webmail-roundcube-sieve-editor.png)

View file

@ -37,7 +37,9 @@ action=554 5.2.2 Quota exceeded (mailbox for user is full)
---
```swaks --from nonexistens@example.org --to chris@auenland.workaround.org
```
swaks --from nonexistens@example.org --to chris@auenland.workaround.org
=== Trying auenland.workaround.org:25...
=== Connected to auenland.workaround.org.
<- 220 auenland ESMTP Postfix (Debian)

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB