2

在 32MB Docker 容器中搭建 Typecho 博客

5 Dec 2024

今天收到了Secure Dragon LLC的邮件,明年OVZ服务器全线涨价:

OpenVZ 128MB plans are increasing to $24.99/year and the new pricing will take effect on the next invoice of 2025.

比locvps的特价香港机都贵了,只好搬到自己服务器上用 Docker 搭建了。

制作 Docker 构建配置

系统选型

  1. 肯定是 alpine 了。
  2. 因为 Typecho 1.2.1 对最新的 PHP 8.3 有一点兼容问题,而最新的 apline 3.20 默认安装的是 PHP 8.3,我偷懒直接选择 alpine 3.18 作为基准镜像,这样 apk 命令安装的 PHP 就是 8.1 版了。

环境还原

  1. 原版的 OVZ 主机是安装了 dropbear,容器内也会装上
  2. php-fpm 也是少了的
  3. 安装 typecho 依赖的 php 扩展

AI 生成配置

这年头不会全自己写了,先丢给 GPT,然后自己检查了一般,最终得到下边的Dockerfile

# 使用 Alpine 作为基础镜像
FROM alpine:3.18

# 设置时区为上海
RUN apk add --no-cache tzdata && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone && \
    apk del tzdata

# 安装必要的工具和依赖
RUN apk add --no-cache curl unzip dropbear lighttpd php php-ctype php-curl php-dom php-fpm php-iconv php-gd php-json php-openssl php-pdo php-pdo_sqlite php-sqlite3 php-xml php-xmlreader php-phar php-posix php-ftp php-session php-bcmath php-sockets php-mbstring php-tokenizer bc

# 动态获取 php.ini 路径
RUN PHP_INI_PATH=$(ls /etc/php*/php.ini | head -n 1) && \
    sed -i "s|;*cgi.fix_pathinfo=.*|cgi.fix_pathinfo=1|i" $PHP_INI_PATH && \
    sed -i 's@^;date.timezone.*@date.timezone = Asia/Shanghai@' $PHP_INI_PATH && \
    sed -i "s@^memory_limit.*@memory_limit = 12M@" $PHP_INI_PATH && \
    PHPFPM_CONF_PATH=$(ls /etc/php*/php-fpm.d/www.conf | head -n 1) && \
    sed -i "s@^user = nobody@user = lighttpd@" $PHPFPM_CONF_PATH && \
    sed -i "s@^group = nobody@group = lighttpd@" $PHPFPM_CONF_PATH

# 创建 lighttpd 的日志目录
RUN mkdir -p /var/log/lighttpd && \
    chown -R lighttpd:lighttpd /var/log/lighttpd

# 设置工作目录
WORKDIR /srv

# 暴露 lighttpd 端口
EXPOSE 80 443

# 暴露 dropbear 端口(使用参数设定)
ARG DROPBEAR_PORT=22
ENV DROPBEAR_PORT=${DROPBEAR_PORT}
EXPOSE ${DROPBEAR_PORT}

# 启动脚本
COPY start.sh /start.sh
RUN chmod +x /start.sh

# 启动 dropbear 和 lighttpd
CMD ["/start.sh"]

以及start.sh

#!/bin/sh

# 检查 /srv/index.php 是否存在
if [ ! -f /srv/index.php ]; then
    # 下载并解压最新的 Typecho 版本
    curl -L -o typecho.zip $(curl -s https://api.github.com/repos/typecho/typecho/releases/latest | grep 'browser_download_url' | cut -d '"' -f 4)
    unzip typecho.zip -d /srv
    rm typecho.zip
fi

# 设置权限
chown -R lighttpd:lighttpd /srv

# 检查并创建 /config/dropbear 目录
if [ ! -d /config/dropbear ]; then
    mkdir -p /config/dropbear
fi

# 生成 dropbear 主机密钥到 /config/dropbear 目录
if [ ! -f /config/dropbear/dropbear_rsa_host_key ]; then
    dropbearkey -t rsa -f /config/dropbear/dropbear_rsa_host_key
fi
if [ ! -f /config/dropbear/dropbear_ecdsa_host_key ]; then
    dropbearkey -t ecdsa -f /config/dropbear/dropbear_ecdsa_host_key
fi
if [ ! -f /config/dropbear/dropbear_ed25519_host_key ]; then
    dropbearkey -t ed25519 -f /config/dropbear/dropbear_ed25519_host_key
fi

# 检查并创建 /config/lighttpd 目录
if [ ! -d /config/lighttpd ]; then
    mkdir -p /config/lighttpd
fi

# 检查 /config/lighttpd/lighttpd.conf 是否存在,如果不存在则复制 /etc/lighttpd 目录下的所有文件到 /config/lighttpd 目录下
if [ ! -f /config/lighttpd/lighttpd.conf ]; then
    cp -r /etc/lighttpd/* /config/lighttpd/
fi

# 运行 PHP
/usr/sbin/php-fpm81 -c /etc/php81/php-fpm.conf

# 检查并运行 /srv/boot.sh 如果存在
if [ -f /srv/boot.sh ]; then
    chmod +x /srv/boot.sh
    /srv/boot.sh &  # 在后台运行
fi

# 启动 dropbear,指定密钥文件路径
/usr/sbin/dropbear -E -p ${DROPBEAR_PORT} -r /config/dropbear/dropbear_rsa_host_key -r /config/dropbear/dropbear_ecdsa_host_key -r /config/dropbear/dropbear_ed25519_host_key &

# 启动 lighttpd,指定配置文件路径
/usr/sbin/lighttpd -D -f /config/lighttpd/lighttpd.conf

构建并运行容器

把上边两个文件放在/data/32mb下,然后进入这个目录执行命令

docker build -t alpine-typecho .

接着是运行容器,这个容器必须限制到32MB内存以及32MB交换分区(SWAP)

docker run -d --memory 32m --memory-swap 64m -p 80:80 -p 443:443 -p 22:22 -v ~/.ssh:/root/.ssh -v /data/32mb/config:/config -v /data/32mb/www:/srv --name typecho-container --restart always alpine-typecho
# -v /data/32mb/config:/config 是映射配置目录
# -v /data/32mb/www:/srv 是映射 typecho 目录

启动容器后会自动安装Typecho到/srv目录,也就是VPS上的/data/32mb/www目录,lighttpd的配置文件也会生成到/data/32mb/config/lighttpd/lighttpd.conf

修改配置

  1. 直接执行下边的命令启动相关模块

    sed -i 's/#   include "mod_fastcgi_fpm.conf"/   include "mod_fastcgi_fpm.conf\ninclude "mod_ssl.conf""/g' /data/32mb/config/lighttpd/lighttpd.conf
    sed -i 's/#    "mod_rewrite","/    "mod_rewrite","/g' /data/32mb/config/lighttpd/lighttpd.conf
    sed -i 's/#    "mod_redirect","/    "mod_redirect","/g' /data/32mb/config/lighttpd/lighttpd.conf
    cat > /data/32mb/config/lighttpd/mod_ssl.conf << EOF
    server.modules += ("mod_openssl")
    server.modules += ("mod_setenv")
    $HTTP["scheme"] == "https" {
     setenv.add-response-header  = ( "Strict-Transport-Security" => "max-age=63072000; includeSubdomains; ")
    }
    EOF
  2. 这里不单独说明 SSL 证书申请了网上都有
  3. 新增虚拟主机,修改/data/32mb/config/lighttpd/lighttpd.conf,在最后一行之前加入

    # virtual host
    $HTTP["host"] =~ "^(www.)?32mb.cc" {
     server.document-root = "/srv"
     accesslog.filename = "/config/logs/32mb.cc.log"
     $HTTP["scheme"] == "http" {
         # redirect to https, port 443:
         url.redirect = (".*" => "https://%0$0")
     }
    }
    $SERVER["socket"] == ":443" {
     ssl.engine = "enable"
     ssl.pemfile = "/config/32mb.cc.pem"
     $HTTP["host"] =~ "(^|www\.)32mb.cc" {
         ssl.pemfile = "/config/32mb.cc.pem"
         # 这是 typecho 的伪静态规则,其他程序自行修改
         url.rewrite-if-not-file = (
             "^/(admin|usr)/(.*)" => "/$1/$2",
             "^/(.*)$" => "/index.php/$1"
         )
     }
    }

    然后重启容器访问绑定好的域名就行了

    docker restart alpine-typecho

    题外话

    因为使用Docker跑web服务,无需SSH就能执行命令了,甚至可以关闭dropbear把内存压缩到16M,12M的样子,不过没测过。

2

实时显示 VPS 资源占用

27 Jun 2023

把下面的脚本保存为status.sh,建议放到网站根目录下,脚本会保存占用数据到脚本虽在目录。

#!/bin/bash

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

while true; do
    # 获取CPU占用百分比
    cpu_usage=$(grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage "%"}')

    # 获取内存占用百分比
    mem_usage=$(free -m | awk '/Mem/ {usage = $3 / $2 * 100; printf "%.2f%", usage}')

    # 获取根目录占用百分比
    disk_usage=$(df -h / | awk '/\// {usage = $(NF-1); print usage}')

    # 构建JSON对象
    json='{ "cpu_usage": "'$cpu_usage'", "mem_usage": "'$mem_usage'", "disk_usage": "'$disk_usage'" }'

    # 将JSON对象写入文件
    echo "$json" > "$script_dir/system_usage.json"

    sleep 1
done

然后增加一个开机启动项,或者手动执行下面的命令

no /path/to/status.sh > /dev/null &

然后你就可以通过https://你的域名/system_usage.json获取到占用数据,比如32mb.cc的实时占用数据地址是https://32mb.cc/usr/themes/blackleft/status/system_usage.json
至于前端怎么写,问 ChatGPT 最快

6

32MB 起航教程

25 Mar 2022

第一步 买 VPS

https://securedragon.net/clients/cart.php?a=add&pid=299
发工单让客服改成 32MB

第二步 配置基础环境

换系统,换成Alpine,这个真的很省资源

wget https://www.moerats.com/usr/shell/alpine.sh && bash alpine.sh

安装 Dropbear

apk update
apk add dropbear

修改 Dropbear 端口

vi /etc/init.d/dropbear

DROPBEAR_OPTS=""

改成

DROPBEAR_OPTS="-p 你想要的 SSH 端口(不要与 OpenSSH端口冲突)"

启动 Dropbear

service dropbear start
rc-update add dropbear default

重新通过 Dropbear 端口登录 SSH
卸载 OpenSSH

service sshd stop
apk del openssh

因为 Dropbear 不支持 SFTP,所以安装 lrzsz 替代,这个可以在 Xshell 终端直接拖拽文件进去

apk add wget gcc g++ make
wget https://ohse.de/uwe/releases/lrzsz-0.12.20.tar.gz
tar -xf lrzsz-0.12.20.tar.gz
cd lrzsz-0.12.20/
./configure
make; make install
ln -s /usr/local/bin/lrz /usr/local/bin/rz
ln -s /usr/local/bin/lsz /usr/local/bin/sz

安装 Lighttpd,别试 Caddy 了,虽然 Caddy 配置 SSL 方便,但是实际没有 Lighttpd 省资源

apk add lighttpd
rc-update add lighttpd default
rc-service lighttpd restart

安装 PHP,这个年头了,当然要 PHP 7啦,毕竟 Typecho 都迁移到 PHP 7.2 + 了

apk add php7 php7-ctype php7-curl php7-dom php7-fpm php7-iconv php7-gd php7-json php7-openssl php7-pdo php7-pdo_sqlite php7-sqlite3 php7-xml php7-xmlreader  php7-phar php7-posix php7-ftp php7-session php7-bcmath php7-mcrypt php7-sockets php7-mbstring  php7-tokenizer

# 修改 PHP 配置
sed -i 's@^;date.timezone.*@date.timezone = Asia/Shanghai@' /etc/php7/php.ini
sed -i "s@^memory_limit.*@memory_limit = 12M@" /etc/php7/php.ini
sed -i "s|;*cgi.fix_pathinfo=.*|cgi.fix_pathinfo=1|i" /etc/php7/php.ini

# 修改 Lighttpd 配置,启用 FastCGI、SSL、rewrite、redirect
sed -i 's/#   include "mod_fastcgi.conf"/   include "mod_fastcgi.conf\ninclude "mod_ssl.conf""/g' /etc/lighttpd/lighttpd.conf
sed -i 's/#    "mod_rewrite","/    "mod_rewrite","/g' /etc/lighttpd/lighttpd.conf
sed -i 's/#    "mod_redirect","/    "mod_redirect","/g' /etc/lighttpd/lighttpd.conf
rc-service lighttpd restart
cat > /etc/lighttpd/mod_ssl.conf <<EOF
server.modules += ("mod_openssl")
server.modules += ("mod_setenv")
$HTTP["scheme"] == "https" {
    setenv.add-response-header  = ( "Strict-Transport-Security" => "max-age=63072000; includeSubdomains; ")
}

第三步 配置虚拟主机

先使用acme.sh申请SSL证书,Lighttpd要求SSL证书和私钥放在一个文件里

mkdir -p /web/32mb.cc
chown -R lighttpd.lighttpd /web/32mb.cc
export DP_Id=xxx
export DP_Key=xxx
acme.sh --issue --dns dns_dp -d 32mb.cc -d *.32mb.cc
acme.sh --install-cert -d 32mb.cc \
--key-file /web/32mb.cc.key \
--fullchain-file /web/32mb.cc.crt \
--reloadcmd "cat /web/32mb.cc.key /web/32mb.cc.crt > /web/32mb.cc.pem; service lighttpd restart"

新增虚拟主机,修改/etc/lighttpd/lighttpd.conf,在最后一行之前加入

# virtual host
$HTTP["host"] =~ "^(www.)?32mb.cc" {
    server.document-root = "/web/32mb.cc"
    accesslog.filename = "/web/32mb.cc.log"
    $HTTP["scheme"] == "http" {
        # redirect to https, port 443:
        url.redirect = (".*" => "https://%0$0")
    }
}
$SERVER["socket"] == ":443" {
    ssl.engine = "enable"
    ssl.pemfile = "/web/32mb.cc.pem"
    $HTTP["host"] =~ "(^|www\.)32mb.cc" {
        ssl.pemfile = "/web/32mb.cc.pem"
        # 这是 typecho 的伪静态规则,其他程序自行修改
        url.rewrite-if-not-file = (
            "^/(admin|usr)/(.*)" => "/$1/$2",
            "^/(.*)$" => "/index.php/$1"
        )
    }
}

然后就是安装 Typecho 啦

3

再次回到 32MB

24 Mar 2022

如果您看到这篇文章,表示您的 32MB 已经回来了。

这次是在 SecureDragon 的 VPS 上搭建的。

    页码: