2024-10-12 11:28:00
前段时间我购买了几年的 CloudCone 特价机炸了,导致服务中断快一个星期,再加上没有定期做备份,服务无法快速恢复。我开始寻找其他服务商的机器,兜兜转转最终选择了搬瓦工的,因为看它比较老牌,口碑还不错,且国内直连的线路良好,在此发出一个 我的邀请码,你可以通过这个链接购买服务器,为博主提供微薄返利以资助网站的持续运营。
另外小扯一句,你可能会注意到我博客的更新频率有所下降。但其实是因为我以此同时还在维护另外一个名为 保罗的小窝 的网站。个人对于博客的定义是稍微正式的内容,而这个小窝更多的是分享随笔和流水账,各位可以自行选择订阅。
此前一直都在用 OneInstack 脚本来部署环境,尝试用它重新部署,却发现 MariaDB 无法正常安装。国内国外访问同一个包的下载地址居然行为是不一样的(国外出现 404)。我选择构建安装,时间太长太复杂,且选择 Caddy 作为 Web 服务器后,居然虚拟主机都没有创建成功,我怀疑脚本是不是根本就没做好 Caddy 的适配...
OneInstack 此前也爆过供应链挂马的问题,据说是被国内公司收购了之后出现,虽然作者承诺修复,但我仍对其安全性存在质疑。再三抉择后,只能忍痛放弃 OneInstack,打算从零开始学习部署属于自己的 Ubuntu 服务器环境了!
你需要一定的 Linux 使用基础才能更好的阅读本文,实际安装过程可能有些许曲折,本文对部分流程做了次序优化,可能存在欠缺需要自行分析和解决(例如某些软件包需要自行安装),虽然有一部分在编写过程中在虚拟机上重新执行确认过,但还是以实际操作为准吧!
选择自己纯手工配置环境最主要的原因就是 PHP,它除了一个 FPM 服务以外,还需要一个 Web 服务器才能将项目跑起来,它并不能像 NodeJS 那样自己就是一个 HTTP 服务。再加上数据库服务放在相对实际的环境下可以更好的编写脚本实现一键备份等功能。使用 K8S / Docker 部署应用会更方便,但受限于成本、服务器数量和硬件配置等因素,自己纯手工配置环境依旧是首选方案。
PHP 8.3
NodeJS
在使用 Caddy 之前我都是选择 Nginx 作为 Web 服务器,Nginx 技术成熟但配置起来没有 Caddy 那么容易,Caddy 作为后起之秀其评价也还不错,它还自带 SSL 证书签发功能,而且不会出现因 HTTPS 证书导致的 IP 泄漏问题。此前也使用过它 部署环境 有些许经验,这次直接使用它作为生产环境我认为也是没有问题的!
MariaDB 是开源版本的 MySQL,此前保罗一直在用,因此就没有考虑 MySQL。
PHP 版本此前都是 7x,最新版本都是 8x,如果你要使用 PHP 的包管理器 Composer 管理项目,那么直接用 PHP 8 是最省时的选择(如果要用 7x,你还需要旧版本的 Composer,太麻烦了,我一个新手根本不会弄,还不如升级自己的代码)
phpMyAdmin 是一款运行在 PHP 下的老牌数据库管理软件,我们首先安装它也能确认 PHP 是否能正常与数据库进行连接。
NodeJS 也是我现在使用 Nuxt (Vue) 和 Remix (React) 框架构建应用所必备的,这里我们使用 FNM 安装,并配置 PM2 用于持续化启动网站。
在开始之前我也推荐安装一些实用软件,你可以根据自己的需求选择安装。
安装 htop
以实时查看服务器配置:
sudo apt install vim htop fastfetch
安装 net-tools
以查看网络相关信息
sudo apt install net-tools
安装 trash-cli
,防止文件直接删除,无法被恢复:
sudo apt install trash-cli
vim ~/.bash_aliases
alias rm='trash-put'
安装 ufw
以控制服务器的入站出站流量,选择性打开服务端口,防止被外部 IP 扫描减少安全风险。如果你的云服务商支持在后台自定义设置防火墙规则(例如阿里云),那么可以选择不安装。
sudo apt update
sudo apt install ufw
# 设置默认策略为拒绝所有传入连接
sudo ufw default deny incoming
# 设置默认允许所有传出连接
sudo ufw default allow outgoing
# 允许 TCP 端口 6755
sudo ufw allow 6755/tcp
# 检查状态
sudo ufw status verbose
# 启用 UFW
sudo ufw enable
安装 openssh-server
以允许远程操控服务器。如果是服务商提供的 Ubuntu,可能已经默认安装,直接跳过。
sudo apt install openssh-server
编辑配置文件,修改端口,禁用密码访问,改为使用公私钥形式访问服务器。
sudo vim /etc/ssh/sshd_config
Port 5678
PubkeyAuthentication yes
PasswordAuthentication no
编辑文件 authorized_keys
添加私钥,以后将会用主机的公钥与服务器中的私钥配对连接。如果没有密钥对可以使用 ssh-keygen
生成一个,这里建议使用 ssh-keygen -t ed25519
指定算法生成(因为 Mac 那边新版本已经不支持默认的 RSA 了)
vim ~/.ssh/authorized_keys
重启服务器的 sshd
服务
sudo systemctl restart sshd
(可选)配置主机的 config
文件,指定使用证书命中到服务器。
Host MyServer
Port 5678
User root
Hostname 10.7.9.103
PreferredAuthentications publickey
IdentityFile ~/.ssh/myserver_ed25519
参考 官网说明 安装即可。
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
Caddy 已经完成安装并自动启动。如果你选择安装了 ufw
防火墙,允许外部访问 80 443 端口:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
新建站点目录
mkdir /var/www
mkdir /var/www/html
此时我们还不需要配置任何网站,你可以使用 wget
或在浏览器上访问服务器对应的 IP,确认 Caddy 已经正常启动。
sudo apt install mariadb-server
sudo mysql_secure_installation
注意这里
Enter current password for root
第一次要求输入密码直接跳过,到后续第二次询问Change the root password?
再设置。至于它为什么会问两次密码,我也不是很清楚。我尝试过只在第一次要求的时候输入,但在第二次询问时跳过,这样做会导致最后什么密码都无法登录...
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
haven't set the root password yet, you should just press enter here.
Enter current password for root (enter for none):
OK, successfully used password, moving on...
Setting the root password or using the unix_socket ensures that nobody
can log into the MariaDB root user without the proper authorisation.
You already have your root account protected, so you can safely answer 'n'.
Switch to unix_socket authentication [Y/n] n
... skipping.
You already have your root account protected, so you can safely answer 'n'.
Change the root password? [Y/n] n
... skipping.
By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.
Remove anonymous users? [Y/n] y
... Success!
Normally, root should only be allowed to connect from 'localhost'. This
ensures that someone cannot guess at the root password from the network.
Disallow root login remotely? [Y/n] y
... Success!
By default, MariaDB comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.
Remove test database and access to it? [Y/n] y
- Dropping test database...
... Success!
- Removing privileges on test database...
... Success!
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
Reload privilege tables now? [Y/n] y
... Success!
Cleaning up...
All done! If you've completed all of the above steps, your MariaDB
installation should now be secure.
Thanks for using MariaDB!
输入一条命令完成安装:
sudo apt install redis-server -y
在安装之前,我们还需要新增一个 Ubuntu 软件源:
sudo add-apt-repository ppa:ondrej/php
sudo apt update
安装 php
、composer
及其对应的扩展(你可以根据自己的需要来安装):
sudo apt install php8.3 php8.3-curl php8.3-fpm php8.3-mysql php8.3-redis php8.3-mbstring php8.3-xml
sudo apt install composer
⚠️ 注意:使用apt
安装部分 PHP 扩展时可能会导致安装apache2
依赖项,后续需要将其禁用,可能使用apt
来安装并不是一个最佳方案
编辑 php.ini
配置文件,取消生产环境隐藏报错的设置,好让我们接下来更好的排查问题,后期可视情况还原。
vim /etc/php/8.3/fpm/php.ini
error_reporting = E_ALL & ~E_NOTICE & ~E_WARNING
display_errors = On
通过命令 service php8.3-fpm status
查看当前 php8.3-fpm
服务配置文件的路径。
include=/etc/php/8.3/fpm/pool.d/*.conf
可以看到引入了一个 pool
的配置文件,ls
列出当前文件夹下所有文件。
ls /etc/php/8.3/fpm/pool.d/
www.conf
使用 vim /etc/php/8.3/fpm/pool.d/www.conf
查看配置文件,即可看到 sock
的地址。
listen = /run/php/php8.3-fpm.sock
复制下来,后续我们需要将路径粘贴在 Caddy 的配置里面,后续粘贴到 Caddy 的字符串如下:
unix//run/php/php8.3-fpm.sock
首先创建所需的文件夹:
sudo mkdir /var/www/
sudo mkdir /var/www/html
sudo mkdir /var/www/html/default
还记得前面提到的 PHP Socks 路径嘛,这里将会用到,首先开始编辑 Caddyfile
配置文件:
vim /etc/caddy/Caddyfile
新增一条虚拟主机记录,由于访问地址是服务器 IP 自身,无法签 SSL 证书,因此直接选择自签即可。
10.7.9.103 {
tls internal
root * /var/www/html/default
php_fastcgi unix//run/php/php8.3-fpm.sock
file_server
}
重启服务,理论上没有任何问题。
service caddy restart
我们可以创建一个 index.php
文件,测试是否可以正常连接到 PHP:
vim /var/www/html/default/index.php
<?php
phpinfo();
使用浏览器访问链接 https://10.7.9.103
,理论上将会显示当前 PHP 的运行信息。
从 官网 上下载最新版本,之后解压在 /var/www/html/default/phpMyAdmin
目录下。
官网上的版本已经内置了所需要的 Composer 依赖,我尝试过本地自行安装,但遇到了错误,原因不明,也不想花心思继续排查了,只要自己项目正常就行。
使用浏览器访问链接 https://10.7.9.103/phpMyAdmin
,输入账号密码,你可能会遇到如下错误:
mysqli::real_connect(): (HY000/1698): Access denied for user 'root'@'localhost'`
此时主要检查两种情况,一个是前面密码的设置问题(可以用 mariadb
命令尝试登录),另外一个则可能是 root
账号所对应的 Host 的问题。
截至本文编写过程在虚拟机里重新执行确认时,并未出现这个错误,就挺奇怪的,但还是提供一下之前的解决方案
使用 mariadb -u root -p
命令登录,输入下面的命令,这里参考了 OneInstack 的源码。
# xxxx 是你的密码,可以和之前设置的一致
GRANT ALL PRIVILEGES ON *.* TO root@'localhost' IDENTIFIED BY "xxxx" WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON *.* TO root@'127.0.0.1' IDENTIFIED BY "xxxx" WITH GRANT OPTION;
FLUSH PRIVILEGES;
再次尝试,应该就能正常登录了。
我注册了 CloudFlare R2 存储桶来完成服务器的备份数据存储,实测国内的银联信用卡也可以使用。可以在服务器上使用命令行工具 rclone
来将文件存储至 R2 存储桶,后期整理一个备份脚本定期执行即可。
https://developers.cloudflare.com/r2/examples/rclone/
Ensure you are running rclone v1.59 or greater (rclone downloads ↗). Versions prior to v1.59 may return HTTP 401: Unauthorized errors
CloudFlare 文档描述对 rclone
版本有要求,apt
下的似乎比较老,因此直接根据 官网教程 直接安装最新版本(截至本文编写过程,最新版本是 v1.68.0)
sudo -v ; curl https://rclone.org/install.sh | sudo bash
先在 CloudFlare 后台新建 R2 存储桶,并创建一个 API 令牌以供 rclone
程序进行连接。你将会得到以下几个数据:
在编写自动化脚本之前,需要添加对应的存储桶配置,后期可直接使用对应的命令和配置上传文件。
rclone config
No remotes found, make a new one?
n) New remote
s) Set configuration password
q) Quit config
n/s/q> n
Enter name for new remote.
name> cloudflare
Option Storage.
Type of storage to configure.
Choose a number from below, or type in your own value.
4 (Amazon S3 Compliant Storage Providers including AWS, Alibaba, ArvanCloud, Ceph, ChinaMobile, Cloudflare, DigitalOcean, Dreamhost, GCS, HuaweiOBS, IBMCOS, IDrive, IONOS, LyveCloud, Leviia, Liara, Linode, Magalu, Minio, Netease, Petabox, RackCorp, Rclone, Scaleway, SeaweedFS, StackPath, Storj, Synology, TencentCOS, Wasabi, Qiniu and others) -> 6 (Cloudflare R2 Storage)
Option provider.
Choose your S3 provider.
Choose a number from below, or type in your own value.
Press Enter to leave empty.
6 / Cloudflare R2 Storage
\ (Cloudflare)
Option env_auth.
Get AWS credentials from runtime (environment variables or EC2/ECS meta data if no env vars).
Only applies if access_key_id and secret_access_key is blank.
Choose a number from below, or type in your own boolean value (true or false).
Press Enter for the default (false).
1 / Enter AWS credentials in the next step.
\ (false)
2 / Get AWS credentials from the environment (env vars or IAM).
\ (true)
回车继续,输入 access_key_id
和 secret_access_key
Option access_key_id.
AWS Access Key ID.
Leave blank for anonymous access or runtime credentials.
Enter a value. Press Enter to leave empty.
access_key_id>
Option secret_access_key.
AWS Secret Access Key (password).
Leave blank for anonymous access or runtime credentials.
Enter a value. Press Enter to leave empty.
secret_access_key>
Option region.
Region to connect to.
Choose a number from below, or type in your own value.
Press Enter to leave empty.
1 / R2 buckets are automatically distributed across Cloudflare's data centers for low latency.
\ (auto)
region> 1
Option endpoint.
Endpoint for S3 API.
Required when using an S3 clone.
Enter a value. Press Enter to leave empty.
endpoint>
Edit advanced config?
y) Yes
n) No (default)
y/n> n
Configuration complete.
Options:
- type: s3
- provider: Cloudflare
- access_key_id:
- secret_access_key:
- region: auto
- endpoint:
Keep this "cloudflare" remote?
y) Yes this is OK (default)
e) Edit this remote
d) Delete this remote
y/e/d> y
配置完成后,可使用命令列出存储桶的数据和上传文件,确保连接正常。
rclone tree cloudflare:存储桶名称
理论上能够正常列出存储桶下的内容,如果不能正常显示,可以从下面几个方向排查:
打包生成备份的过程在这里不作详细介绍,大致就是使用 mysqldump
导出数据库,之后使用 tar
打包压缩站点数据,最后使用 rclone copy
命令将所有文件上传,定期手动或自动化执行都是可以的。
cd ~/backup/2024-10-21/
mysqldump -u root -p home > home.sql
rclone copy . cloudflare:存储桶名称/2024-10-21/
在 官网 上选择对应的环境,即可生成一键安装脚本,我选择了当前最新的 LTS 版本和 fnm
,你可根据自己的需要安装对应的版本。
# installs fnm (Fast Node Manager)
curl -fsSL https://fnm.vercel.app/install | bash
# activate fnm
source ~/.bashrc
# download and install Node.js
fnm use --install-if-missing 20
# verifies the right Node.js version is in the environment
node -v # should print `v20.17.0`
# verifies the right npm version is in the environment
npm -v # should print `10.8.2`
接着来安装 PM2,这是项目持久化运行在服务器上所必备的。
pm2 startup
pm2 start ./ecosystem.config.cjs(应用程序的示例,以实际为准)
pm2 save
这样服务器重启后,也能自动启动 pm2
服务以及对应的应用程序。
配置一个 NodeJS 项目到 Caddy 非常简单,基本上就只是一个端口转发规则而已。
paul.ren {
reverse_proxy localhost:3001
# 添加以下配置以处理 /upload 路径
handle /upload/* {
root * /var/www/html/legacy.paul.ren/public
file_server
}
handle /static/* {
root * /var/www/html/legacy.paul.ren/public
file_server
}
}
可以编辑 ~/.bash_aliases
文件自定义自己的快捷命令,快速定位到 Caddyfile
配置等。
感谢 @提莫 同学对本文中一些内容的指正,由于本人的运维经验不足,虽然已经花了不少时间重试其中的某些步骤,但仍然可能有所不足和缺漏,有什么问题可以在下方留言,我会尽力为大家解答。
2024-07-05 14:35:00
近期要把公司的新官网项目给收尾了,准备打包部署发布到线上环境,我们主要采用的 CircleCI 和 K8S 负责 CICD,就是期间经常会遇到 K8S 的超时错误导致构建失败。
虽然不清楚具体的错误原因,但我发现构建过程中 Dockerfile
生产出来的镜像文件实在是太大了,达到了惊人的 1G 多,想着这样传输镜像的时间肯定会慢,是否因此导致构建失败的概率提升呢?前文详见日记《继续准备 NextJS 新官网项目(二)》
这篇文章我们将以官方的配置文件作为基础二次修改,将应用的构建过程放在当前系统环境来完成,最后将产物打包成 Docker 镜像,以实现大小优化。
想着之前自己部署 NuxtJS 的时候发现它在生产环境下最终运行的是一个 server.mjs
文件,这意味着我或许并不需要安装一大堆 node_modules
依赖,然后再执行 pnpm build && pnpm start
的方式来启动服务。这些最终构建好的代码,小到不足 50MB。
那么 NextJS 可以吗,简单搜索看了下,它是可以做到的。我是从它们官方提供的 Dockerfile 里面找到的这个设置项 output,比较隐蔽。
Next.js can automatically create a
standalone
folder that copies only the necessary files for a production deployment including select files innode_modules
.To leverage this automatic copying you can enable it in your
next.config.js
:
module.exports = {
output: "standalone",
}
修改成这种模式后,意味着项目生产环境的启动方式不再是 pnpm start
了,继续这样操作的时候 NextJS 的命令行工具也会对此进行提示。
"next start" does not work with "output: standalone" configuration. Use "node .next/standalone/server.js" instead.
那么在此之前我是怎么做的呢,这是项目之前的 Dockerfile
,可以看到构建、运行应用的过程均在里面完成(并非阶段构建),也因此导致最后的镜像略大。
FROM node:20.15-alpine AS runner
# 定义一个名为 ENV 的参数,默认值为 dev
ARG BUILD_ENV=prod
# Create app directory
WORKDIR /app
RUN addgroup --system --gid 941 nodejs
RUN adduser --system --uid 941 nextjs
COPY . ./
WORKDIR ./
# 如果 BUILD_ENV 为 dev,则复制 .env.dev 到 .env.local
RUN if [ "$BUILD_ENV" = "dev" ]; then cp .env.dev .env.local; fi
RUN chmod 0777 .
RUN npx --yes pnpm install
RUN npx pnpm build
USER nextjs
EXPOSE 3000
ENV PORT 3000
CMD ["npm", "start"]
考虑到我司已经在使用 CircleCI 负责构建应用,K8S 只负责打包并运行构建结果即可,我根据官方的 Dockerfile
最终整理出了一份自己的,供各位参考:
FROM node:20.15-alpine AS runner
ENV NODE_ENV production
# Create app directory
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY public /app/public
# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --chown=nextjs:nodejs .next/standalone ./
COPY --chown=nextjs:nodejs .next/static .next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
CMD ["ls", "-l"]
# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
CMD HOSTNAME="0.0.0.0" node server.js
这份 Dockerfile
相较于前面的版本,他多出了一个复制 static
(位于项目内 .next/static
) 和 public
(位于项目内 /public
)文件的步骤,据官方描述说是这些文件应由 CDN 处理,但实际情况我们用的 CDN 属于融合 CDN(不知道是不是这么说,类似 CloudFlare 那种自动缓存和回源的),因此不需要额外处理单独托管的静态文件。
因为没有在 Dockerfile
里面安装依赖和构建应用了,因此需要在当前的系统环境下,已经通过 pnpm build
完成 NextJS 的构建过程。
我自己的服务器并没有强大的资源和性能,只有一个机器跑多个服务的使用场景。如果改用传统 Jenkins + SSH + PM2 的部署方式,也是一样轻松了不少,以往需要在运行机器上执行极其缓慢的 pnpm build
也将提前在 Jenkins 机器上完成。通过 SCP 的方式传输构建产物,到运行机器上只需替换掉对应的资源,重启 PM2 就能完成,这里就不再具体提供实现过程了,有需要建议自行尝试摸索。
2024-06-27 21:08:00
这 NextJS 可真是把我给恶心 🤢 到了,项目里使用 next-international
这个库配置了站点多语言,按照其文档中的 配置说明,需要修改 middleware
中间件的配置。
而项目当中遇到了跨域的接口请求,不知道什么原因后端配置不生效。于是我打算增加 next.config.js
文件中编写的 rewrites
规则。结果我发现一旦使用了 NextJS 的中间件,这些 rewrites
配置居然通通全部直接无视了 🤡🤡🤡
const nextConfig = {
async rewrites() {
return [
{
source: '/paul/:slug*/',
destination: 'https://paul.ren/:slug*/',
}
]
}
};
// 此时访问 项目链接/paul 显示 404
因为注释掉多语言需要加入中间件的代码之后,rewrites
中的规则重新生效了...
也不确定这是不是 Bug,但这种巨型框架层面的 Bug 可不是我一个小彩笔能解决的,Bug 解决不了,但需求仍然要继续做的。我想到直接使用 Caddy 来帮我做这件事,反向代理某一个业务的接口之后强行设置 CORS 的 Header 头,允许任意的跨域请求,随意使用。
通过 Docker 使用 Caddy 是最简单的方法,且不会干预到实体系统环境,这里我使用了 Docker Desktop 作为演示。点击顶部搜索栏搜索 caddy
,下载最新版本的镜像,点击 Run 按钮使用它创建启动容器。
在设置里填入对应的端口号,这里我只设置 80 端口的映射,确保端口号没有被占用就行。
设置完成后容器将会自动启动并且持续运行,使用浏览器访问对应映射好的端口号(我这是 7888),如果能正常访问则服务正常运行,就可以继续设置了。此时点开容器面板选择 Exec
Tab 进入该容器的终端界面,输入以下命令进入配置文件的编辑界面:
vi /etc/caddy/Caddyfile
修改配置文件的内容,具体如下:
:80 {
reverse_proxy https://paul.ren {
header_up Host {upstream_hostport}
header_up X-Real-IP {remote}
header_up X-Forwarded-For {remote}
header_up X-Forwarded-Port {server_port}
header_up X-Forwarded-Proto {scheme}
}
@cors_preflight {
method OPTIONS
header Origin *
}
handle @cors_preflight {
respond 204
header Access-Control-Allow-Origin "*"
header Access-Control-Allow-Methods "GET, POST, OPTIONS"
header Access-Control-Allow-Headers "*"
}
header {
Access-Control-Allow-Origin *
Access-Control-Allow-Methods "GET, POST, OPTIONS"
}
}
保存后重启容器,使用浏览器重新访问对应链接,应该会直接显示对应「被反向代理」网站的内容,说明反向代理配置成功。
之后修改 NextJS 项目那边的环境变量,使接口请求经过我们配置好的 Caddy 代理,如无意外则一切正常使用,这就变相解决了 NextJS 内置的反向代理存在 Bug 的问题。
2024-05-22 00:54:00
蓝底白字的 官方通告 已经出了,结果也是在预料之内,看完这篇懂得都懂,这就是语言的艺术。官方的主要出发点是为了平息事件对于公众的影响,但即便如此我相信大多数人的看法都是明智的。
前有假结婚后分财产,后有谈恋爱“同居”大额生活费不算诈骗,版本也在不断快速迭代,但总体而言法律依旧是在偏向女性的,这也就是为什么会出现这么多令人讨厌的 T0 “小仙女”了吧。
关于这份通告不同人也有不同的解读,一方面认为这是“真反转”,认为女方不是诈骗,反倒是胖猫姐姐涉嫌夸大诬陷女方。另一方面则是和我想的一样,女方确实存在诈骗行为了。
我认为从胖猫角度上来说,他可能认为钱给够了女方就会喜欢他。(可能太恋爱脑了,真以为自己满足对方的要求就能得到她了)从女方角度上来说,如果根本就不喜欢他,她应该及时拒绝,而不是让男方一昧的“爆金币”。(都没长期共同居住过都敢要这么多钱了,难道官方鼓励在恋爱中大手大脚的花费吗,显然不可能啊)这就涉及到个人的道德底线问题了。
针对这份通告也是有个知乎回答特别有意思,说是给真正的捞女提供了思路:
- 男方转给女方的钱要适当返还,这样可以被警方认定是正常男女恋爱关系
- 女方要让男方用恋爱记、小荷包等 App 功能共同存钱,并且坚定表示是奔着结婚去的,这样即使钱到手了之后立马分手,警方无法认定自己诈骗
- 要带男方去见见自己的亲友,介绍给家属,之后再以感情不和为理由分手即可
想起来之前也有个段子,说唯一合法的方式就是和别人的老婆在一起,既不会分财产,也不会让男方承担较大风险(虽然还有强奸罪,但最起码财产保住了)。
看完上述例子之后感觉不无道理,只是这样做也确实不道德。
我朋友说“古代男尊女卑 是有他的道理的”,虽然说着有点难听,但前人之鉴的确不能忽视,现实情况的确有不少东西来来去去都是一次轮回罢了。不然你看苹果的设计,以及前端框架的 SSR,本就是一场轮回,玩的都是前面玩剩下的。
女人狠起来连自己人都打,法律偏袒女性的本意是保护女性,但众多事件的发生已经足以证明它已经渐渐变为了某些人的特权,作为广大男同胞的一员,只能对此唏嘘不已。法律的本意是保护,而不是滥用,是为了让你真正遇到危险时能发挥出最大的作用。
T0 “小仙女”们的恶心行为,应该是被众人所鄙夷的,而不是被她们的“逐渐深入”渐渐变成“官方正确”。
在这里我只能呼吁身边的女性朋友们都能够清醒起来,不要变成像她们那样的负面教材吧... 对不合适的人勇敢拒绝,而不是反复纠缠。
男生真的不是不想谈恋爱不想结婚,只是想要遇到一个合适的人确实太困难了。胖猫事件警醒了不少男同胞,告诉他们这并不是少见的个例,这种畸形的价值观已经影响到不少人了。再加上现在各种 App 大数据的推送机制,只会推送用户更喜欢的内容,进一步加大了这种毒鸡汤的扩散。只会让这些人更自以为是,认为男性单方面的付出就是理所应当的,可男生的钱也不是大风刮来的不是么。
我自然还是期望能遇到真正欣赏我、喜欢我的人,尽管可能比较难,但并不代表没有可能。纯爱战士依旧存在,只是概率比较低罢了。(很荣幸自己的一位友链朋友就是这样)
只是从我的角度来看,自由恋爱确实变得越来越困难和不可信,宁愿相信自由恋爱或许还不如相信家里人介绍的,至少家庭背景是相对有保障的,并且通过他们的父母也能一定程度上可以了解他们的子女可能是怎么样的一个人,除非是那种关系并不熟络的朋友。
至于为什么我至今一直都单身,有人说这是上天在保护你,虽然有点自我安慰的感觉,但总比急急忙忙遇到一个要我爆金币的捞女要好吧... 这大环境就是被这样的人搅浑浊了,我结婚的同事都表示已经跟不上版本了。
在真正开始一段恋爱关系之前,我也在认真思考过,自己是否能付出一个合格男友必要的责任。如果不行我自然也不会随意和她们建立关系,我认为这才是对对方的尊重。宁可不爱,也别伤害。因为感情也确实需要一定的磨合,这也无疑是真正的挑战...
我曾经有一段黑历史,在这段黑历史的加持下让我有很长的一段时间惧怕异性,我或许更适合先结识异性朋友,从普通朋友做起,消除恐惧,后面才能更从容的面对真正适合自己的人。
2023-12-15 17:37:00
个人感觉 2022 年编写的日记质量都蛮高的,不如采用原先的分类形式+时间排序链接对应日记的形式,算是个小的创新?
由于相册内容堆积了将近一年的量没上传,再加上本次总结涉及到的信息量略大整理起来比较有难度,所以咕咕到了现在。2023 年的总结,估计还是不太适合继续沿用这样的模式了。
截至今天(2023 年 12 月 23 日),这篇总结依旧没有被完成,此时此刻我还得开始筹划编写 2023 年的总结了,先挂在这里后续随着图片上传再慢慢完善吧。
用 PS 自制了一个直播间的模版,还以此写了一个网页弹幕机(目前已经失效,暂不考虑重写了),和其他人项目不同的特点是可以使用浏览器的语音播报功能。装修的貌似是挺漂亮了,但观众却还是只有那几个人。
上家是使用 Jenkins 完成项目的自动化部署流程的,只要 Git 提交代码,就会触发一个 WebHook 发送到 Jenkins 对应的链接,无疑这么做能大大节省新代码上线所需要的人力成本。
而我的服务器资源匮乏,决定采用了曲线救国的方法,将自己家的 Windows 电脑通过 Frp 转发服务到 Gitea 服务器上就实现了这个操作,这么做部署性能强劲,不可能造成其他服务卡顿,缺点就是不想一直开机(有独立显卡功耗高),不能保证随时可用。也许弄一个远程启动电源的方案可以解决这个问题。
配置 Jenkins 期间主要遇到了发送 Curl 消息时出现编码错误的问题,是 @Eric 大佬帮我更换系统集成环境解决的。
以及各种个性化的操作,但基本都是用系统环境变量解决。例如获取 Git 最新提交记录的内容,并发送给机器人
主要还是年末操作 Jenkins 的时候误删了上传的所有文件,这种大批量的老数据最后的备份只有 2021 年的,之后产生的新数据都只能重新更新上去,这种反复枯燥的操作,只能把希望放在编写自动化脚本上了。
在春节假期期间,我成功编写了一段自动化生成文章占位图的 Shell 代码,可以将不同尺寸不同分辨率的动漫插画,统一处理成 16:10 的分辨率,并且保持原有的比例进行裁切。原理是遍历文件夹下所有图片,并采用 imgmagick 工具进行处理,最终重新编号导出到指定的文件夹下。
相册图片则还需要后期补上,估计加上 Curl 的流程就可以实现。拍摄的照片是最容易的,少数内容是手动拼接或打码的则还需要重新手工处理。
今年和去年一样,并没有新增什么好看实用的开源项目,以个人学习尝试与经验分享的角度分别开设了两个文档类项目。前者记录我折腾捣鼓过程的草稿性质代码,后者分享我编写代码的一些个人实践经验。都是我入职新公司之后发起的。
其他项目维护的并不频繁,我的 Single 和 Fantasy 主题也没增加什么新的特色功能(追求稳定)
个人网站 依旧是我主要的维护对象,包括但不限于以此发起的功能代码维护、日常内容编写,各种小设计等等。隔壁 @Innei 的开源项目 Mix Space 越来越有人气了,但我的程序还是挺垃圾的,考虑到自己服务器配置较低、老数据兼容等各种问题(我日记的数据最早从 2018 年就开始积累起来了),因此暂时不考虑更换后端的技术栈。
PHP 它也的确足够用了不是么,为了学技术故意上一套看似很厉害的方案,实际配置起来还更麻烦的。关于自己个人网站的维护经历,我在后期也会整理出一篇文章,欢迎持续关注本博客。
前端方面,前台有计划考虑使用 Vue 3 和 Nuxt,目前推出了一个 测试版本,重新设计了一套新的 UI,依旧是水绿色为主要颜色设计的,这个颜色和初音未来的主题色十分的相似呢。
后端方面,主要重构了项目相关内容,将 JSON 存储改为了数据库存储,这样大概可以优化程序执行的内存占用(所有的项目内容都存在了一个 JSON 文件里面,而且后台是直接编辑 JSON 文件而不是提供表单式的界面)
【待完善】
偶然通过 QQ 空间看到了这个后台项目设计起初的模样,原来早在 2020 年就换成了现在的这套设计风格了呀。去年增加了换配色的功能,但感觉并不满意,考虑接下来结合 Less 实现更多样化的配色,尝试增加更多样化的底纹?
奇趣起始页
Single 主题
Fantasy 主题(赞助版)
一些与项目维护(包括公司项目)与整活的过程,可以看下这些日记:
2022-04-03:直播写项目 / 被 🐱 抓 / 远程协助同学整电脑
今年的工作和求职过程可以说是坎坎坷坷,好在我运气不错,有个比较好的结局。至于为什么离职了,那你大可听我继续往下细说。
3 月初被叫去谈话了一次,说是公司接下来开始全员居家办公,公司的电脑什么的大概率要被收回去,只能用自己电脑干活。这说明了一个问题,就是公司的现金流估计紧张起来了。虽然公司也有不少同事是远程工作的,但我还是喜欢出门走走。
明天要把公司电脑的数据清空一下了,接下来我就是全程在家办公的「死宅」一个了,在颠废的路上持续前进着,工资没涨、技术没进步...
在干活的某一天,因为此前我的一些个人想法,有部分图片资源没经过打包器,导致发布生产环境时命中了旧的缓存,但又不允许清除 CDN 缓存(可能是没有管理权限)被老板说了一句,这个操作简单但反复,修改的项目很多,能用简单的办法解决谁想用难的呢。
老板:你得搞掂这个事,不然换图片这个事都搞不掂,是不是该考虑考虑是否胜任当前岗位?
我从这句话感觉到他貌似 Diss 了我,有那种“随时被开”的威胁口气。
后续就被老板说工作态度消极,扣了不少工资(年前公司已经全员扣了一次了,年初的时候还说有机会调整正常,实际并没有,这能不消极吗)
下午和老板私下谈话了,他还是觉得我现在这样的工作态度有问题,最后结果就是继续降工资咯,我也不知道还会在这里待多久了。
做业务真的就是“解决问题”而已,即便是用最烂,可维护性最差的方法也多多少少能做出来。也许这就是为什么公司此前的项目平均水准都不太高的原因吧。写了这么久的 React 之后,第一感觉就是接触到好的项目源码之后,即便代码看不懂,但之后会逐渐明白他为什么要这么做,有什么好处,眼光确实是会不一样的。接下来这段时间我还是尽量多去看看书和文章吧,不然再这样下去迟早也会废了的。
这件事发生之后,我只想着怎么能在这里继续挖掘出剩余的潜在价值了,合作关系已经开始逐渐崩塌,呆不长久了。
随后我的事情很快就被传到隔壁深圳同学那了,真是丢脸丢到外地去了。
再仔细思考一下当时和老板谈话的时候,他口中说的能继续加薪的同事,其实干的杂活也确实不少,甚至晚上经常加班解决(所有人的提交记录都有个可视化图,他确实显得特别积极),这要是不给加就很过分了。
我依然还在尝试着把代码写得更好,但这样做貌似在公司里体现的意义并不大。毕竟客户确实可不是看你代码写的好不好的,而是看能不能及时的满足需求而已。写得好,也就只是对自己的工作负责,接下来修改起来也会没那么吃力些。
甚至因为这件事情,我爸还想过我要不要去转行做设计,我自然是拒绝了。一是我完全没经验,二是我缺乏必要的技术。例如插画设计我就完全不会,同行竞争力很低,就算有机会面试不也是现场被拒啊。
我把这件事情发到了脉脉,并没有人抓住重点不说,还被人咬文嚼字继续 PUA 了一顿,这种事情发生之后,一度把我的心态搞到炸裂。估计是因为大厂员工普遍高压力无处释放把,自己过的不顺也好好 PUA 别人一把,反正彻底对这个平台无语了。但在意外看了一份别人本科生的简历过后,我感觉我也许并不算太差。
继续呆在这家公司,一个人孤军奋战维护一个“屎坑”后台项目,并不能让我获得什么新的能力提升,和朋友、群友们聊过之后,果断的选择了裸辞。我的学历不高,学历焦虑还是挺严重的,但是升学考试对我来说还是太困难了。
准备简历的过程也比较麻烦,相较于之前的简历,主要做了这些改进:
离职相关的事情也和朋友聊过,@Eric 准备去字节继续做开发,@Kevin 打算去香港读研,@MJ 想着去外国留学持续提升。不得不说,他们个个都比我要强多了!
失业期间我也在网上刷(学)着各种面试题,之后我在 Boss 上投递简历陆续去面试,一共面试了 3 家。
在 @Innei 的引介下认识了现在公司的老板,进而入职了现在的公司(在此之前还面试了两家都没成,我也没有什么合适的选择了)入职后阅读代码的能力还是 Debug 的能力都有所提升,由于维护的是一个在线会议项目,我也借此熟悉了 WebRTC 及一系列的相关技术(虽然都不算深入),团队氛围还是工作环境整体都是比较不错的。
这些都是我入职公司之后的一些事,我挑了一些或许比较有料的内容出来。可能和上面的有所重复,但我不想修改了,整理起来确实太困难了。
...
我在新公司里主要做的事情基本都是迭代产品和修复 Bug(必要时重构),也算是上手项目代码比较合适的方法。即便如此也不能保证自己编写过程中不会产生新的 Bug,因为你没法想象其他人之前会用什么奇怪的方式写。在你的认知里「这个东西」是这个作用,在他们的认知里或许是别的作用(还有一些 Bug 的修复,解决了问题但命名与实际作用不符),想要彻底解决这种问题就只能慢慢重构优化了。
按照大佬们的计划,今年暂时没有自己主导的新项目。但我认为在接下来的一年一定会有的!
今年年初我奶奶去世了。到老家的第一天去探望的大姑丈,后续也因病去世。人生有时候就是这么短暂,所以忙碌过后,还是好好享受下生活吧。
本来奶奶年纪大了手脚不灵活,想着买车之后开车回家,让奶奶亲自坐上我开的车,看来这个想法现在是做不到了啊。
约了好多家中介看了好几次房,新楼盘和老楼盘都看了下,但几乎都是过了过眼瘾。毕竟我家境确实一般,并不像其他人家里有矿想买就买,在我上班之前家里基本上就是“月光族”,这也就是为什么我一台爸妈买的游戏本能从上学用到上班还在坚持了。在家里收入不高的情况下,的确应该节俭一些。
参加了一次隆重的婚礼,朋友圈也围观了不少人的婚礼。可能是我与他们关系普通,或者对方家庭条件问题只叫了家里人吧,我并没有被他们受邀参加。对于我这种从来没谈过恋爱的人来说,只能是无比的羡慕啊。
和老妈商量后,给家里购置了鱼缸,养了点小宠物的感觉还行,有活物之后,可以闲着没事对着它发呆了。
晚上回到家,我老妈下单的鱼缸送到了。花时间拼装了下水泵,清洁了缸体和装饰物,就差点小鱼了。我还是更希望能再去淘点大件的装饰物(小桥城堡房子什么的),这样使得整体内容就更加丰富一些了。
年前花 300 多块钱做了一套造型。虽然看上去效果还不错,但是依旧没有女生会多瞧我一眼。
现在日常喜欢在淘宝、B 站、咸鱼等平台上查找可爱的周边,像是动漫抱枕,手办,T 恤等等,因为实在是太可爱了,简直是猛男的最爱啊,忍不住的说不定就下手了啊。
第一次是在西区里遇到一个骑电动车的做推广,说是什么新店开业参与抽奖,结果要求我给他看支付宝的花呗记录什么的。感觉就挺有问题。
第二次则是在 🐑 了的期间,我妈接到了一个自称京东客服的电话,他很熟练的爆出我家地址,在对方要求我安装钉钉共享屏幕我就感觉到不对劲了,上网搜索之后就是实打实的诈骗,保留了对话语音,但是我懒,没整理出对应的日记。
感觉现在本科就是入场券,IT 行业内普遍认为本科达到了烂大街的水平了。因为这个原因,我有几位同学也尝试开始自学考试升本。
他那句话「往死里学」让我印象深刻,(考本科,尤其是数学)明明就是自己不擅长的事情,为什么还要反复再逼自己去做呢。没有爱好支撑,凭什么去坚持下去?问他几点钟睡觉,结果也是两三点。近期互联网公司这么多的猝死事件,实在是让我感到害怕。
但他们在深圳平常工作就挺劳累了,下班还时不时在群里约其他同学上号玩游戏,想要在这种疲惫的环境下好好学习还是非常考验一个人的心态的。
也有其他朋友提供了建议,例如远程授课的海外大学,就是需要语言能力,以及不少的 Money,你懂的。
刷微信的时候又看到了那种提升学历的广告文,说是考试会变难,什么专业都要考高等数学和英语了,这么搞真的是难上加难咯!(虽然计算机专业也必须要考)不过得知了自学考试的概念,看百科上的说明说是这种考试比全日制要难,可现在的工作大多数都需要全日制吧,自学考试的水分和全日制比,难道还是全日制的更吃香么?
也有人说,求职的时候公司看你不是全日制本科,也会直接 Pass 掉,既然如此那我还有什么信心去争取呢,不如多提升一下自己的技术水平或影响力,争取获得更多的内推机会更合适。
三月中旬左右去打了最后一针疫苗,至少自己不会变成重症患者了。
三月底,自己住的地方直接来了一个密切接触者,直接整栋楼封楼了,每个人都要做登记。
吃着晚饭的时候,外面突然响起了敲门声,在想着是不是楼下邻居又来找麻烦(噪音)了。结果我妈看到是穿着防护服的工作人员,没错,我们这栋楼被封控了...
六月离职后独自一人出去吃了顿麦当劳,结果却感冒了。@Innei 说估计是离职之后太焦虑了免疫力下降了,我觉得有道理。在有工作的时候感到不快,在没工作的的时候感到更不快了!
11 月底,疫情又开始扩散起来了,公司办公地点附近一片区域全部封锁。一部分同事不能过来上班,结果没两天,公司所在位置直接被封了。那天刚下车准备上班,结果就只能回家远程办公了。
结果年初突然宣布全部解除封锁,也不提供免费且强制性的核酸检测了,自然年底都如约而至“羊”了,全员陆陆续续感染新冠在家休息,还好公司所有前端几乎都是错开休息的,项目方面貌似并没有太大的影响。
近期疫情已经逐渐常态化了,我这开始不提倡低风险人群做核酸,且开始付费做核酸。价格 2.5 混管,13 块单管。呆在家的好处自然是能降低感染风险,但女朋友嘛,总不可能天上飞下来一只吧...
后续我爸单位也有同事 🐑 了,导致我们一家自觉“隔离”,不参加聚会等活动了,少吃了一顿大餐。
圣诞节那天,我妈也说自己开始有症状(估计也是自己同事传过来的),但我还没事,因为常态化之后,只要没症状就得去上班。结果那天去到公司立马就开始喉咙不舒服了... 之后就开始在家休息,我妈吐槽说现在你们吃的都是 🐑 人做的 🐑 餐了。
我妈发烧了,而且头微微疼,可能羊了,但我还没有症状,按照规定即使我 🐑 也得正常回公司上班
甚至我不舒服的其中一天,我妈那还遇到了诈骗电话,还好我人没有彻底傻掉。加上她并不会操作,骗子气急败坏,什么话都让他说出来了。
这鬼病毒都 6 天了,结果自己还没完全好起来。还干了一件或许终身难忘的一件事情,为了配置自动化备份网站的功能,直接把自己网站的图片资源全部删除了,糟透了!躲得过初一,还是躲不过初五啊...
为了弥补这个错误,我只好开始研究自动化脚本,以快速可靠的方法覆盖掉 404 的资源(截止 2023 年 12 月 31 日,依旧存在不少资源无法被恢复)详见上面 编写了一段自动化 Shell 章节。
还没开始就结束了。这件事情的起源还是因为我在 B 站一个原神的视频下方发了一条评论。
原神这么火 我还是遇不到一个玩原神的女朋友 😭
办了招行的工作细胞储蓄卡和初音未来的信用卡各一张
疑似被猫抓,挨了几针子
唯一一次写的比较 Emo 的日记?其实就是想找对象了
回老家过中秋节
亲戚的孩子都满月了,而我还是毫无进度
游戏方面基本上和去年一样,由于购入了新的台式主机,因此玩了四海兄弟和大表哥,感觉需要时间才能好好体验,不像现在的快餐游戏随时肝完体力就想赶紧下线做其他事情。
换设备之前的体验是真的糟心,《四海兄弟:重制版》最低画质分辨率 30 FPS 都不能稳定,也不知道我是怎么玩下去的==
依旧是休闲萌系番。
老爸用的红米 Note 8 购于 2020 年,今年年末他的手机电池续航下降,我细看出现了鼓包的现象,他嫌弃手机比较慢,就给他更换了一台红米 Note 12,是刚出不久的新机。原先想买一台二手更大内存的红米 K30,到货后感觉屏幕有些许瑕疵,考虑到后期的系统更新年限,我还是选择退货买了新的机型。
9 月组装了自己的第一台台式电脑,是真正意义上自己的电脑,自己的工资,自己完成的组装。其中显卡是大头,去掉它不到 5K,加上它差不多 9.5K 了。而上一台台式电脑还是我上小学的时候爸妈通过亲戚介绍去电脑城装的,配置很低,就是一般的办公配置。
这台电脑的配置如下:
主板:华硕 B660M D4 Wifi
CPU:英特尔 i5 12400
内存:金士顿 32G DDR4
硬盘:西数 1TB SN570(不太够用,现在非常后悔)
GPU:蓝宝石 RX6750 XT 超白金
我想加设一台显示器提高办公效率,找老板申请了,最终选择了小米的 27 寸 2K 分辨率的一款。之前用的 Windows 主机居然带不动两台显示器(Intel 你也太不争气了吧),于是征用了公司一台闲置的 Mac Mini,M1 处理器,8 + 256 的丐版,但貌似还能胜任我的日常工作。
2022-11-12:简单买了点东西的双十一 / 公司配了显示器和 Mac
年前购买了 iPad Mini 6,不是全新的,屏幕上有细微划痕,边框无磕碰。就是在环境温度很低(15 - 20度左右)的时候貌似性能释放会有问题,出现游戏画面掉帧,不知道是我机器的问题还是通病。
这个现象在我 iPhone 上也偶尔会出现,并不是百分之百会有
后续这台机器玩了几个月就给弄坏寄修了,CPU 烧坏不能用 Wifi 上网,低价出给维修的了,血亏血亏!
家里的 39 寸联想智能电视购于 2014 年,今年除夕前一天就坏了,春晚都没得看了。年后参考网上的评测还是选择了它,价格最有性价比,具体体验咋样就后期再说吧。
如果你对这类文章都比较感兴趣,也欢迎你来看看我朋友的同类文章,写的都挺不错的 😂
@Innei:2022 · 在绝望中前行
@折影轻梦:2022,没有记忆的一年
相较以往写总结的人更少了,而我也咕到了现在才完成。首先感谢你能看到这里,其次感谢在这一年里不断让我进步,让我快乐的各位朋友们,祝你们新年快乐~