DuetG Blog

Keep It Simple, Stupid

  • 给WordPress双重身份验证增加应用程序密码支持

    给WordPress双重身份验证增加应用程序密码支持

    2020年底发布的Wordpress5.6增加了应用程序密码(Application Passwords)功能,这个功能是建立在整合Application Passwords插件代码的基础上的。

    事实上Wordpress官方GitHub账号上还有一款双重身份验证插件,也就是Two-Factor插件。尽管在Wordpress.org的插件库里,这款插件的作者既没有写作官方商业插件的Automattic,也没写作开源插件的WordPress Contributors,而是写为Plugin Contributors。但鉴于它的代码在官方GitHub账号上托管的身份,它无疑算是官方的两步验证插件。只是这款插件已经发布了这么久,并没有见官方像应用程序密码一样把它的代码整合进核心代码。也不知道是不是为了给其他第三方商业两步验证插件留条生路。

    本着简单免费的原则,我还是选择了官方身份的这款免费插件。不过用了之后发现了些小问题——这款插件直接对已经开启了两步验证的账号禁用了API登录的请求。这导致我的IFTTT没有办法再和Wordpress互动。这是Two-Factor默认的设置,倒也不是bug,只不过它并没有给一个能处理的用户界面来修改。

    最终的解决方案是Application Passwords的作者在GitHub上给出来的,不过也只是一段代码,而非是增加一个用户界面选项。

    add_filter( 'two_factor_user_api_login_enable', function( $enable ) {
        // Allow API login when using an application password even with 2fa enabled.
        if ( did_action( 'application_password_did_authenticate' ) ) {
            return true;
        }
    
        return $enable;
    } );

    在Wordpress.org上插件库里,Application Passwords的介绍中也有这段代码的描述,只不过任何人都没有将它做成一个用户界面选项。然而Application Passwords的代码已经整合进了Wordpress核心代码里,以后恐怕也不太有可能看到有这个选项了,毕竟它本来就是Two-Factor的功能。

    把这段代码粘到主题的functions.php里就可以了。不过如果嫌麻烦,我也做了一个简单的插件,直接下载安装激活就可以了(本身就还是这段代码)。

  • 在家部署MinIO实现S3自由

    在家部署MinIO实现S3自由

    这是一篇与随后准备写的部署Mastodon实例相关的文章。

    S3是Simple Storage Service的缩写,是亚马逊提供的一种云存储模式,目前已是一种主流的云存储,大多数前端服务都支持S3接入,大多数的商业云存储服务也都兼容S3。

    商业云存储目前大多数都是付费模式,个别限时或限量的免费体验版整体来说使用起来都不很自由。

    借助开源软件的免费优势,我们今天来尝试在家庭服务器上部署自托管的MinIO对象存储服务。MinIO本身是兼容S3的,作为一种低成本解决方案,一旦部署好就可以基本替代商业云存储。要注意的是,低成本不代表无成本,基本替代也很难成为完美替代。

    首先我们家中需要一台服务器(或者是服务器上的虚拟机)和一个域名。另外家庭宽带也需要公网IP,宽带上下行速度会直接影响文件传输速度。如果没有公网IP想用frp穿透的话,其数据传输速度自然会更加受影响,所以建议要有公网IP。后面会以安装好Docker的Debian/Ubuntu系统举例,当然你要用Podman也没问题。

    先使用路由器的动态DNS(DDNS)功能把家庭宽带的公网IP自动更新到域名托管的DNS服务。然后再用路由器防火墙的端口映射功能把WAN口的9000端口映射到你服务器的9000端口。

    然后再服务器里建立工作文件夹,并生成MinIO的配置文件

    mkdir minio
    cd minio
    vim minioconfig

    将如下内容按实际修改后粘贴进去。MinIO更多的环境变量可以参见这里

    # MINIO_ROOT_USER 和 MINIO_ROOT_PASSWORD 设置 MinIO 服务器的 root 帐户。 
    # 该用户拥有对部署中的任何资源执行 S3 和管理 API 操作的不受限制的权限。 
    # 如将其备注掉不设置则使用默认值“minioadmin:minioadmin”。 
    # MinIO 建议设置非默认值作为最佳实践,无论环境如何
    
    MINIO_ROOT_USER=myminioadmin
    MINIO_ROOT_PASSWORD=minio-secret-key-change-me
    
    # MINIO_VOLUMES 设置用于 MinIO 服务器的存储卷或路径。
    
    MINIO_VOLUMES="/mnt/data"
    
    # MINIO_SERVER_URL 设置与 MinIO 服务器一起使用的本地计算机的主机名 
    # MinIO 假设您的网络控制界面可以正确将此主机名解析到本地计算机 
    # 取消注释以下行,并将该值替换为本地计算机的正确主机名和 MinIO 服务器的端口(默认为 9000)。
    # 如https://你的域名:9000
    
    #MINIO_SERVER_URL="https://minio.example.net:9000"

    填入之后保存退出vim,之后来准备Docker Compose文件

    vim docker-compose.yml

    我们部署一个单节点单驱动的实例,进入编辑界面后把下面的内容按实际修改后填入

    version: '2'
    
    services:
      minio:
        container_name: minio
        command: server --console-address ":9090"
        environment:
          - MINIO_CONFIG_ENV_FILE=/etc/config.env
        image: quay.io/minio/minio:latest
        volumes:
          - ./data:/mnt/data
          - ./minioconfig:/etc/config.env
        restart: always
        ports:
          - "9001:9000"
          - "9090:9090"

    这里设定工作文件夹下的data文件夹是整个存储的目录,你可以按需求把第11行冒号前面的./data修改成你想要的目录。或者你可以在工作目录下建立一个名为data的链接到你想要的目标目录。也可以用nfs协议把内网其他位置的硬盘目录映射到这个data上,总之按你的需要来处理存储位置的设置。同时为了后面使用NGINX来实现反向代理端口,容器的9000端口先映射到主机的9001端口了。

    保存退出后就可以下载镜像生成容器了

    docker compose up -d

    容器顺利生成并启动后,我们来配置NGINX,首先设置站点配置文件

    vim /etc/nginx/sites-available/minio

    将下面的内容贴入编辑界面

    server {
            listen 9000 ssl default_server;
            listen [::]:9000 ssl default_server;
    
            include snippets/snakeoil.conf;
    
            ssl_session_cache shared:le_nginx_SSL:10m;
            ssl_session_timeout 1440m;
            ssl_session_tickets off;
    
            ssl_protocols TLSv1.2 TLSv1.3;
            ssl_prefer_server_ciphers off;
    
            ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
    
            server_name _;
    
            # To allow special characters in headers
            ignore_invalid_headers off;
            # Allow any size file to be uploaded.
            # Set to a value such as 1000m; to restrict file size to a specific value
            client_max_body_size 1000m;
            # To disable buffering
            proxy_buffering off;
            proxy_request_buffering off;
    
            location / {
                    # First attempt to serve request as file, then
                    # as directory, then fall back to displaying a 404.
                    # try_files $uri $uri/ =404;
                    proxy_set_header Host $http_host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_set_header X-Forwarded-Proto $scheme;
    
                    proxy_connect_timeout 300;
                    # Default is HTTP/1, keepalive is only enabled in HTTP/1.1
                    proxy_http_version 1.1;
                    proxy_set_header Connection "";
                    chunked_transfer_encoding off;
    
                    proxy_pass http://127.0.0.1:9001;
            }
    }

    这里我们假定了证书的储存位置是/etc/nginx/snippets/snakeoil.conf写的

    ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
    ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;

    如果你希望是别的位置请修改相应的内容。保存退出后使用ln命令将其链接到enabled文件夹,并删掉其中的default配置

    ln -s /etc/nginx/sites-available/minio /etc/nginx/sites-enabled/
    rm /etc/nginx/sites-enabled/default

    然后我们使用acme.sh的DNS API功能来申请证书,使用DNS API申请证书不需要80端口,非常适合国内家庭宽带申请证书,而且acme.sh也支持大量的DNS服务商。具体的申请方法可参见这篇文章的前半部分。

    证书设置完毕后就可以重启NGINX了,也可以先用nginx -t来检查一下配置是否正确。这里我只把MinIO的服务端口9000映射到了公网,而网页控制台的9090端口依然还在内网,从而确保服务的安全。如果你需要在外网访问的话可以考虑使用Tailscale之类的服务来远程访问这台主机的端口。

    最后我们用这台服务器的内网IP加9090端口在浏览器上就可以访问MinIO的网页控制台,使用minioconfig中设置的用户名和密码登录即可。

  • 小米盒子3c刷CoreELEC运行Home Assistant Container

    小米盒子3c刷CoreELEC运行Home Assistant Container

    这是一个穷人乐,如果你像我一样手头上正好有一个小米盒子3c,一条公对公USB数据线,再加上拆机棒、镊子等工具,可以照着下面折腾一下。但如果你只是为了有一个好用的Home Assistant,建议花300左右购入一个Orange Pi 3 LTS自行制作Home Assistant Supervised,或者700多块直接买一个Home Assistant Green,就不要瞎折腾了,更不要为这个专门去收个二手盒子。因为Home Assistant Container只是一个基本的Home Assistant(仅比Home Assistant Core强些),不能安装加载项(Add-ons),更不能安装社区商店(Home Assistant Community Store,可用性以及可玩性都不高。

    Update:今天才知道Home Assistant所有版本都可以安装HACS,被官网那张图骗了好几年……

    如果我上面说的还算清楚,并且你已经看到这里了,那就一起来穷人乐吧。

    刷机包的相关信息和教程在国内是被作者发到了恩山论坛上,时间是22年5月份。文件和源代码托管在全球最大同性交友网站GitHub上,还请自行前去下载。如果没有游戏需求,还请下载9.2-mibox3-1.4,在这个版本仅有CoreELEC。论坛上作者的教程写的还算详尽,请直接参考论坛上的帖子来刷机,这里我主要讲刷机过程中和刷机后的一些问题。至于刷机软件Amlogic USB Burning Tool,作者本人说用的是v2.0.8,其他的版本我也试了几个,结果都不行,但v2.0.8一次成功,所以建议搜索下载这个版本安装。

    如果你没有公对公USB数据线,也可以找两根不要的数据线剪断重接。线准备好了之后,就可以用拆机棒拆机了。这里有篇小米盒子3s的拆机文章,在外壳上和3c基本上是一样的,可以参考一下。经验是要从后往前拆,一旦后面的卡口撬开了,剩下的用拆机片沿着接缝就能划开。不过一开始是比较紧的,不是很好拆。

    拆机完成后就是刷机了,这里我再具体说明一下需要短接的两个测试点是在屏蔽罩的一角和螺丝中间的两个铜测试点,而不是另一边并列三个测试点其中的两个。

    找作者在帖子中所说的步骤准备固件,刷机软件,并把设备与电脑连线等等。软件请务必确保在右侧仅选中“擦除flash”以及下拉菜单里选择“擦除所有”。用左手拿镊子保持短接,右手把电源打开,听到电脑响起硬件插入的响声后立刻取消短接,然后静等烧录完毕。如果中间有问题烧录中止了,请全部断开然后从头重新操作一遍。

    烧录完成后给盒子断电,拔掉数据线。接上HDMI显示器以及键盘或鼠标,插上电源重新开机,就可以看到CoreELEC的启动画面了。

    CoreELEC本身就是一个基于Kodi的极小化Linux系统,所以进去之后修改中文什么的在网上搜一下就可以找得到教程。如果首次登录的时候设置Wi-Fi出错跳过了这个步骤,可以到设置菜单最下面的CoreELEC菜单里重新录入Wi-Fi密码,蓝牙遥控器也需要在这个菜单下重新连接。遥控器进入配对模式是需要按住Home键和菜单键两个不松手,稍等片刻就进入配对模式。如果没有切换成中文就去连接遥控器,会在蓝牙上看到一个名称都是方块的设备,这个就是遥控器没错了。

    如果语言列表里没有中文,需要到插件菜单里下载中文,但在切换中文前请务必把皮肤的字体改为基于Arial,否则整个UI也会变成方块。

    在插件中找到CoreELEC的官方源,在服务程序里找到Docker安装好,并在设置里开启ssh。然后通过ssh进入CoreELEC的命令行,使用以下命令来安装并启动Home Assistant Container。默认用户名是root,默认密码是coreelec。

    docker run --restart always -d --name homeassistant -v ~/homeassistant/config:/config -e TZ=Asia/Shanghai --net=host ghcr.io/home-assistant/home-assistant:stable

    待镜像下载完毕容器跑起来之后,使用你的盒子的IP,端口8123,就可以访问Home Assistant。

    最后说一下遥控器。刚刷好的CoreELEC,把遥控器的连牙蓝上了之后,遥控器的电源键会一键关闭盒子上的系统(并不会彻底关闭电源,也不能开机)。但这种设定很容易带来误操作的麻烦。在网上搜了搜,找到了重新定义keymap的解决方案,一个CoreELEC官方论坛上的帖子。根据官方开发人员的回复,在电脑资源管理器的地址栏输入

     \\你的小米盒子ip\Userdata\keymaps

    可能会需要你输入用户名和密码,由于之前没有修改过密码,所以用户名是root,密码是coreelec。

    打开文件夹后把帖子里的keymaps.xml下载并上传到这个文件夹里,重启以下系统,之后遥控器的电源键就只能触发电源菜单而不会直接关机了。

  • 使用NTFS-3G在macOS上免费读写NTFS驱动器

    使用NTFS-3G在macOS上免费读写NTFS驱动器

    这是个救穷不救急的方法,如果着急用,建议还是花139块(或19.95刀)去买个Paragon NTFS for Mac

    出于个人原因,突然需要从一台老iMac里拷贝出大量的文件,这让我本来就捉襟见肘的储存空间更加的雪上加霜。万般无奈下从京东买了块致态的500GB固态硬盘,把以前笔记本里的1TB机械硬盘换了出来。由于硬盘上本就还有数据,不能格式化,所以就只能在NTFS的文件系统下连接iMac了。

    众所周知macOS对NTFS是只读的,在“因为是个一次性的小需求所以不想花钱买软件”的指导思想下,我只得选择安装商业软件,并在试用期内把问题搞定。然而因为拖延症以及我对“数据读写也要耗时”这个事情从没有像这次一样直观的体验,令我在这台iMac上陆续装了三款免费试用的NTFS装载软件,并逐一都过了期。

    然而我的活儿却还没干完。

    思前想后,决定找一个完全免费的解决方案,通过搜索找到了NTFS-3G这样一款开源跨平台的NTFS驱动。不过想要在macOS上使用,还需要借助macFUSE才可以。下面写的基本上来自于macFUSE官方Wiki上有关NTFS-3G的指导。如果英语不错的话,也可以直接去看原文。

    首先由于需要编译,所以你需要在Mac上安装Xcode,确保Command Line Tools安装到系统。如果没有的话可以在终端里使用这条命令:

    sudo xcode-select --install

    接下来需要安装Homebrew来在终端里实现软件包的安装和管理。

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

    较低版本的macOS是无法通过官网的 .pkg 包完成安装的,会验证你的系统版本,所以用命令行安装是比较稳妥的方式,虽然也会提示版本低,但不会终止安装。

    接下来安装macFUSE,这个直接到官网下载最新的安装包就可以了,目前最新的是macFUSE 4.5.0,注意安装完成后请务必重启系统

    以上准备工作完成后,就可以照着官网Wiki上写的按步骤操作了。其间会有下载和编译的过程,终端窗口不会有任何进度提示,还请耐心等候。

    首先是从Homebrew安装NTFS-3G

    brew tap gromgit/homebrew-fuse
    brew install ntfs-3g-mac

    完成之后插上你的NTFS移动硬盘,macOS识别后在终端使用以下命令查找硬盘分区的名称(如/dev/disk1s1)

    diskutil list

    确定之后就可以手动挂载NFTFS分区了,注意把下面命令中的/dev/disk1s1更换成你硬盘实际分区的名称

    # 还没弹出移动硬盘的话要先把分区卸载掉
    sudo diskutil unmount /dev/disk1s1
    # 再用 ntfs-3g 挂载硬盘
    sudo mkdir /Volumes/NTFS
    sudo /usr/local/bin/ntfs-3g /dev/disk1s1 /Volumes/NTFS -o local -o allow_other -o auto_xattr -o auto_cache
    # 或者上条命令也可以换成下面这条
    sudo /usr/local/sbin/mount_ntfs /dev/disk1s1 /Volumes/NTFS

    代码输入之后,桌面上应该就会显示出来新挂载的NTFS硬盘了,名字会变成NTFS-3G相关的名字,但内容是没错的。打开之后就可以写入数据了。不用的时候点右键推出就好,再用的时候再用命令来挂载。

    至于自动挂载,官方Wiki也给了方法。但由于大多数情况用的还是移动硬盘来回拷贝文件,而不是台式机内多挂了一个硬盘,所以在这里就不再详述了,有需求的直接去Wiki查阅就好。