分类 电脑 下的文章

在 debian 11 的 exim4 里设置 dkim 发信

需求:exim4 发信时,邮件头里打上 dkim 的签名。
步骤:

  1. genrsa -out dkim.key 2048 # 生成一个2048位的私匙
  2. openssl rsa -in dkim.key -out /dev/stdout -pubout -outform PEM # 生成公匙,复制好
  3. chown Debian-exim:Debian-exim dkim.key # 修改权限,让exim能读到私匙
  4. /etc/exim4/exim4.conf.localmacros # 创建自定义的exim参数值,如以下内容:

    DKIM_CANON = relaxed
    DKIM_SELECTOR = dkim
    DKIM_DOMAIN = gd.anqun.org
    DKIM_PRIVATE_KEY = /etc/exim4/dkim/$dkim_selector.key
    DKIM_STRICT = true
  5. vi /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp_smarthost # 默认dkim仅在remote_smtp的trnasport配置文件里,但本例是使用 remote_smtp_smarthost,所以需要将相应的dkim内容从 remote_smtp 复制到 remote_smtp_smarthost,如:

    .ifdef DKIM_DOMAIN
    dkim_domain = DKIM_DOMAIN
    .endif
    .ifdef DKIM_SELECTOR
    dkim_selector = DKIM_SELECTOR
    .endif
    .ifdef DKIM_PRIVATE_KEY
    dkim_private_key = DKIM_PRIVATE_KEY
    .endif
    .ifdef DKIM_CANON
    dkim_canon = DKIM_CANON
    .endif
    .ifdef DKIM_STRICT
    dkim_strict = DKIM_STRICT
    .endif
    .ifdef DKIM_SIGN_HEADERS
    dkim_sign_headers = DKIM_SIGN_HEADERS
    .endif
  6. 之后更新exim4的配置,且重启服务:

    update-exim4.conf.template -r
    update-exim4.conf
    systemctl restart exim4
  7. 到域名的解析面板,设置好相应的txt记录,如将 dkim._domainkey.gd.anqun.org 的 txt 值设置为:v=DKIM1; p=MIIB...
  8. 发封测试邮件到gmail,如成功,在 show original 里会显示 DKIM PASS
  9. 如有错误,请查看日志文件:/var/log/exim4/mainlog

参考:

在 debian 11 系统里安装 osticket 1.17.3

当前最新版本是 osticket 1.17.3, 要求是php8.1。

遇到的第一个问题是:osticket 中显示的工单时间比现时的要快几个小时。debian 11系统里设置的是“中国标准时间 CST”,即北京时间。虽然 osticket 里可以设置时区,但当php.ini里设置时区为 Asia/Shanghai 时,osticket 认为数据库里的时区 CST 是 America/Chicago 时区。

可尝试的方法是按照网友说的,修改 include/class.config.php 里的 function getDbTimezone() 。手动设置时区。如 修改为: $dvd_db_timezone='Asia/Shanghai'; return $dvd_db_timezone;

第二个问题是:管理面板里的 ajax 部分页面不可访问到,如网址 https://example.com/scp/ajax.php/help/tips/settings.system , nginx 会报 404 错误。原因是 osticket 默认只支持 apache 和 iis。

可能问的人多了,它直接放了一个配置内容参考:

server {
        listen 443 ssl http2;
        ssl_certificate           /root/.acme.sh/example.com/fullchain.cer;
        ssl_certificate_key       /root/.acme.sh/example.com/example.com.key;

        root /var/www/example.com/osticket;

        # Add index.php to the list if you are using PHP
        index index.php index.html index.htm index.nginx-debian.html;

        server_name example.com;

        set $path_info "";

        location ~ /include {
            deny all;
            return 403;
        }

        if ($request_uri ~ "^/api(/[^\?]+)") {
            set $path_info $1;
        }

        location ~ ^/api/(?:tickets|tasks).*$ {
            try_files $uri $uri/ /api/http.php?$query_string;
        }

        if ($request_uri ~ "^/scp/.*\.php(/[^\?]+)") {
            set $path_info $1;
        }

        if ($request_uri ~ "^/.*\.php(/[^\?]+)") {
            set $path_info $1;
        }
        location ~ ^/scp/ajax.php/.*$ {
            try_files $uri $uri/ /scp/ajax.php?$query_string;
        }

        location ~ ^/ajax.php/.*$ {
            try_files $uri $uri/ /ajax.php?$query_string;
        }

        location / {
            try_files $uri $uri/ index.php;
        }

        location ~ \.php$ {
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
            fastcgi_param  PATH_INFO        $path_info;
            fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        }
}

server {
        listen 80;
        server_name example.com;
        return 301 https://$server_name$request_uri;
}

第三个问题是:用php的mail()函数发出的邮件正文不可读的,是base64后的代码。原因可能是 osticket 带的发件组件 Laminas-Mail 不是最新的,当环境是php8时,会打乱邮件的标头,exim认为原本多行的标头仅是一行,所以阅读邮件时不能正常识别。

可以尝试的方法是在 osticket/include/laminas-mail/src/Transport/Sendmail.php 文件中,用 if (PHP_VERSION_ID < 80000 && ! $this->isWindowsOs()) { 替换 if (! $this->isWindowsOs()) {

参考:

将 exim4 收取的邮件,用 router 和 transport 转给脚本处理 piping - debian

环境:debian 11, exim4, php8.1, osticket-1.17
需求:用exim接收邮件,将邮件通过 piping 交给 osticket 的 php 脚本处理

过程:

  1. 新增一条 router 配置文件,如 /etc/exim4/conf.d/router/050_exim4-config_osticket
  2. 050_exim4-config_osticket 内容如下。意思要将support@localdomain的邮件交给osticket_transport受理

    osticket_router:
     driver = accept
     local_parts = support
     transport = osticket_transport
  3. 新增 osticket_transport 的配置文件,如 /etc/exim4/conf.d/transport/25_exim4-config_osticket_pipe
  4. 25_exim4-config_osticket_pipe 内容如下。意思是将邮件交给 /var/www/public_html/api/pipe.php 处理

    osticket_transport:
     driver = pipe
     command = /usr/bin/php8.1 /var/www/public_html/api/pipe.php
  5. 将新增的配置文件内容添加到模板中,update-exim4.conf.template -r
  6. 更新exim的配置,update-exim4.conf
  7. 重载 systemctl reload exim4 的服务
  8. 可通过如 exim4 -bt support@localdomain 的命令来检查新设置的 router 和 transport 是否生效

参考:

用 curl 检测端口是否可连接 - http 返回码 - 证书有效期 - Shell

#!/bin/bash

# refer: https://www.baeldung.com/linux/check-website-availablilty and https://curl.se/mail/archive-2022-04/0027.html

trap "exit 1" TERM
export TOP_PID=$$
STDOUTFILE=".tempCurlStdOut" # temp file to store stdout
> $STDOUTFILE # cleans the file content

# Argument parsing follows our specification
for i in "$@"; do
  case $i in
#    http*)
#      WEBPAGE="${i#*=}"
#      shift
#      ;;
    -n=*|--notWantedContent=*)
      NOTWANTEDCONTENT="${i#*=}"
      shift
      ;;
    -r=*|--requiredContent=*)
      REQUIREDCONTENT="${i#*=}"
      shift
      ;;
    -e=*|--email=*)
      EMAIL="${i#*=}"
      shift
      ;;
    -s|--silent)
      SILENT=true
      shift
      ;;
    -t|--testTcpPortOnly)
      TESTTCPPORTONLY=true
      shift
      ;;      
#    *)
#      >&2 echo "Unknown option: $i" # stderr
#      exit 1
#      ;;
    *)
      WEBPAGE="${i#*=}"
      shift      
      ;;
    *)
      ;;
  esac
done

if test -z "$WEBPAGE"; then
    >&2 echo "Missing required URL" # stderr
    exit 1;
fi

function tcp_port_is_open {
  local exit_status_code
#   curl -t '' --connect-timeout 2 -s telnet://"$1:$2" </dev/null
   URL=${WEBPAGE#*//*}
   curl -t '' --connect-timeout 2 -s telnet://"$URL" </dev/null
   exit_status_code=$?
   case $exit_status_code in
     49) return 0 ;;
     *) return "$exit_status_code" ;;
   esac
}

function stdOutput { 
    if ! test "$SILENT" = true; then
        echo "$1"
    fi
}

function stdError { 
    if ! test "$SILENT" = true; then
        >&2 echo "$1" # stderr
    fi
    if ! test -z "$EMAIL"; then
        echo -e "Subject: $WEBPAGE is not working\n\nThe error is: $1" | msmtp $EMAIL
    fi
    kill -s TERM $TOP_PID # abort the script execution
}

if tcp_port_is_open > /dev/null 2>&1 ; then
    if test "$TESTTCPPORTONLY" = true; then
        stdOutput "TCP port is open -> OK"
    else
#            stdOutput "Internet connectivity OK"
    HTTPCODE=$(curl --max-time 5 --silent --write-out %{response_code} --output "$STDOUTFILE" "$WEBPAGE")
    CONTENT=$(<$STDOUTFILE) # if there are no errors, this is the HTML code of the web page
        if test $HTTPCODE -eq 200; then
            stdOutput "HTTP STATUS CODE $HTTPCODE -> OK"
        else
            stdError "HTTP STATUS CODE $HTTPCODE -> Has something gone wrong?"
        fi
        if ! test -z "$NOTWANTEDCONTENT"; then
            if echo "$CONTENT" | grep -iq "$NOTWANTEDCONTENT"; then # case insensitive check
                stdError "Not wanted content '$NOTWANTEDCONTENT'"
            fi
        fi
        if ! test -z "$REQUIREDCONTENT"; then
            if ! echo "$CONTENT" | grep -iq "$REQUIREDCONTENT"; then # case insensitive check
                stdError "Required content '$REQUIREDCONTENT' is absent"
            fi
        fi
        if echo "$WEBPAGE" | grep -iq "https"; then # case insensitive check
            EXPIREDATE=$(curl --max-time 5 --verbose --head --stderr - "$WEBPAGE" | grep "expire date" | cut -d":" -f 2- | date -f - "+%s")
            DAYS=$(( ($EXPIREDATE - $(date "+%s")) / (60*60*24) )) # days remaining to expiration
            if test $DAYS -gt 7; then
                stdOutput "No need to renew the SSL certificate. It will expire in $DAYS days."
            else
                if test $DAYS -gt 0; then
                    stdError "The SSL certificate should be renewed as soon as possible ($DAYS remaining days)."
                else
                    stdError "The SSL certificate IS ALREADY EXPIRED!"
                fi
            fi
        fi
    fi    
else
    stdError "TCP port is close -> Has something gone wrong?"
    exit 1
fi

例子:

liujia@moni:~/check$ ./c.sh anqun.org:3389 -t
TCP port is close -> Has something gone wrong?
liujia@moni:~/check$ ./c.sh anqun.org:3390 -t
TCP port is open -> OK
liujia@moni:~/check$ ./c.sh http://anqun.org:80
HTTP STATUS CODE 200 -> OK
liujia@moni:~/check$ ./c.sh https://anqun.org:443
TCP port is close -> Has something gone wrong?
liujia@moni:~/check$ ./c.sh https://liujia.anqun.org:443
HTTP STATUS CODE 200 -> OK
No need to renew the SSL certificate. It will expire in 59 days.
liujia@moni:~/check$ ./c.sh https://hy.anqun.org:443 -e=i@liujia.anqun.org
TCP port is close -> Has something gone wrong?

在老 debian 里拿掉 DST_Root_CA_X3 的证书

原因:在老版本的 debian 系统里,使用 curl 或 wget 访问 let's Encrypt 发的证书站点时,会提示证书过期。因为证书中包含 DST Root CA X3 的指向,curl 不会自动选择 ISRG Root X1 的证书,且因为 DST Root CA X3 的证书在 2021 年过期,所以 curl 报错。

尝试:

  1. vi /etc/ca-certificates.conf # 编辑证书配置文件内容,注释掉 DST ROOT CA X3 的证书文件,如 !mozilla/DST_Root_CA_X3.crt
  2. update-ca-certificates --fresh # 更新证书

参考: