1 lang
1.1 path
01.Java
a.安装
mv jdk-8u191-linux-x64.tar.gz /usr/local
cd /usr/local
tar -zxvf jdk-8u191-linux-x64.tar.gz
rm -r jdk-8u191-linux-x64.tar.gz
mv jdk1.8.0_191 jdk-1.8.0_191
b.环境变量
gedit /root/.bashrc
export JAVA_HOME=/usr/local/jdk-1.8.0_191
export CLASSPATH=$JAVA_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$PATH
source /root/.bashrc
c.测试
java -version
02.Maven
a.安装
mv apache-maven-3.6.3-bin.tar.gz /usr/local
cd /usr/local
tar -zxvf apache-maven-3.6.3-bin.tar.gz
rm -r apache-maven-3.6.3-bin.tar.gz
b.环境变量
gedit /root/.bashrc
export MAVEN_HOME=/usr/local/apache-maven-3.6.3
export PATH=$MAVEN_HOME/bin:$PATH
source /root/.bashrc
c.测试
mvn -V
03.Tomcat
a.安装
mv apache-tomcat-9.0.78.tar.gz /usr/local
cd /usr/local
tar -zxvf apache-tomcat-9.0.78.tar.gz
rm -r apache-tomcat-9.0.78.tar.gz
b.环境变量
gedit /root/.bashrc
export MAVEN_HOME=/usr/local/apache-tomcat-9.0.78
export PATH=$MAVEN_HOME/bin:$PATH
source /root/.bashrc
c.测试
startup.sh
04.Nodejs-14.21.1,【不支持】npm安装pnpm
a.安装
mv node-v14.21.1-linux-x64 /usr/local
cd /usr/local
tar -zxvf node-v14.21.1-linux-x64
rm -r node-v14.21.1-linux-x64
mv node-v14.21.1 node-14.21.1
b.环境变量
gedit /root/.bashrc
export NODE_HOME=/usr/local/node-14.21.1
export PATH=$NODE_HOME:$NODE_HOME/bin:$NODE_HOME/node-global:$PATH
source /root/.bashrc
c.配置
npm config set prefix "/usr/local/node-14.21.1/node-global"
npm config set cache "/usr/local/node-14.21.1/node-cache"
npm config ls
d.测试
npm -v
node -v
05.Nodejs-16.20.1,【不支持】npm安装pnpm
a.安装
mv node-v16.20.1-linux-x64.tar /usr/local
cd /usr/local
tar -zxvf node-v16.20.1-linux-x64.tar
rm -r node-v16.20.1-linux-x64.tar
mv node-v16.20.1 node-16.20.1
b.环境变量
gedit /root/.bashrc
export NODE_HOME=/usr/local/node-16.20.1
export PATH=$NODE_HOME:$NODE_HOME/bin:$NODE_HOME/node-global:$PATH
source /root/.bashrc
c.配置
npm config set prefix "/usr/local/node-16.20.1/node-global"
npm config set cache "/usr/local/node-16.20.1/node-cache"
npm config ls
d.测试
npm -v
node -v
06.Nodejs-20.18.0,【支持】npm安装pnpm
a.安装
mv node-v20.18.0-linux-x64.tar.gz /usr/local
cd /usr/local
tar -zxvf node-v20.18.0-linux-x64.tar.gz
rm -r node-v20.18.0-linux-x64.tar.gz
mv node-v20.18.0 node-20.18.0
b.环境变量
gedit /root/.bashrc
export NODE_HOME=/usr/local/node-20.18.0
export PATH=$NODE_HOME:$NODE_HOME/bin:$NODE_HOME/node-global/bin:$PATH
source /root/.bashrc
c.配置
npm config set prefix "/usr/local/node-20.18.0/node-global"
npm config set cache "/usr/local/node-20.18.0/node-cache"
npm config ls
d.测试
npm -v
node -v
e.安装
npm install -g pnpm
pnpm set registry http://172.17.8.54/
pnpm set registry https://registry.npmmirror.com
pnpm adduser --registry http://172.17.8.54/
pnpm profile set password --registry http://172.17.8.54/
-----------------------------------------------------------------------------------------------------
pnpm login
j057240
qwER159263
-----------------------------------------------------------------------------------------------------
pnpm c get
pnpm i --registry https://registry.npmmirror.com
07.Navicat
a.权限
mkdir /usr/local/navicat
cd /Ubuntu/software/SQL/Navicat/
mv navicat15-premium-cs.AppImage /usr/local/navicat/navicat15-premium-cs.AppImage
mv navicat.jpg /usr/local/navicat/navicat.jpg
cd /usr/local/navicat/
chmod +x navicat15-premium-cs.AppImage
b.创建Navicat.desktop
gedit /usr/share/applications/Navicat.desktop
c.编辑pycharm.desktop
[Desktop Entry]
Version=1.0
Type=Application
Name=Navicat
Icon=/usr/local/navicat/navicat.jpg
Exec=/usr/local/navicat/navicat15-premium-cs.AppImage
MimeType=application/x-py;
Name[en_US]=Navicat
1.2 debian
00.Debian13包含了超过14,100个新软件包,总数达到近70,000个
a.系统与内核
Linux Kernel: 6.12 LTS 系列
Systemd: 257
GNU C Library: 2.41
b.编译器与工具链
GCC: 14.2
LLVM/Clang: 19 (默认), 17, 18 可选
Python: 3.13
Perl: 5.40
PHP: 8.4
Rustc: 1.85
OpenJDK: 21
c.服务与数据库
Apache: 2.4.64
Nginx: 1.26
MariaDB: 11.8
PostgreSQL: 17
Samba: 4.22
OpenSSH: 10.0p1
OpenSSL: 3.5
d.桌面环境与应用
GNOME: 48
KDE Plasma: 6.3
Xfce: 4.20
LibreOffice: 25.2
GIMP: 3.0.4
Inkscape: 1.4
01.开机设置一:介绍
a.Debian10(Buster)
引入新的Debian 10的主题 “FuturePrototype”
新版本的电脑桌面环境GNOME 3.30、Cinnamon 3.8、KDE Plasma 5.14、MATE 1.20、Xfce 4.12
长期支持版内核4.19.0-4
新的Python 3 (3.7.2)、Perl 5.28、PHP 7.3
iptables替换为 nftables
更新LibreOffice 6.1、GIMP 2.10.8
更新OpenJDK 11、MariaDB 10.3 和 Apache 2.4.38
更新Chromium 73.0、Firefox 60.7
b.默认账号
User(osboxes、osboxes.org)(myslayers、4023615)
Root(root、osboxes.org)(root、4023615)
c.切换root
su -
osboxes.org
d.用户sudo权限
sudo vi /etc/sudoers
osboxes ALL=(ALL:ALL) ALL --打开osboxes全部权限
myslayers ALL=(ALL:ALL) ALL --打开myslayers全部权限
e.安装Vmware Tools
tar -zxvf VMwareTools-10.0.0-2977863.tar.gz
sudo ./vmware-install.pl -y
f.Settings
Privacy -> Off(ScreenLock、LocationServices、Usage&History、PurgeTrash&TemporaryFiles)
Power -> PowerSaving(Never)、Suspend&PowerButton(Off)
KeyboardShortcuts -> HomeFolder(Win+E)、Settings(Win+I)、Browser(Win+1)
KeyboardShortcuts -> add -> 名称(Terminal)、命令(gnome-terminal)、快捷键(Win+R)
Account -> User(myslayers)、Password(40236155)
02.开机设置二:更新工具
a.默认vi-tiny
a.解决默认vi-tiny无法使用“删除键”、“方向键”
sudo vi /etc/vim/vimrc.tiny
set nocompatible --将compatible变nocompatible(方向)
set backspace=2 --末行增加set backspace=2(删除键)
b.将默认vi-tiny替换为vim
apt-get update && apt-get -y remove vim-common && apt-get -y install vim*
b.国内镜像源
a.备份默认镜像源
sudo cp /etc/apt/sources.list /etc/apt/sources.list_bak
a.切换tsinghua镜像源
sudo apt install apt-transport-https ca-certificates
b.查看tsinghua镜像源
vi /etc/apt/sources.list
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free
c.tasksel命令
a.tasksel一键搭建LAMP服务器、邮件服务器、DNS服务器
sudo tasksel install lamp-server
sudo tasksel install mail-server
sudo tasksel install dns-server
b.切换桌面
sudo tasksel -> KDE Plasma、GNOME、Xfce、Cinnamon、web server、print server、SSH server -> 空格选
update-alternatives --config x-session-manager --切换桌面系统
d.IPv4+DNS
a.修改网卡配置:dhcp,vi /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
allow-hotplug ens33
iface ens33 inet dhcp
b.修改网卡配置:vi /etc/network/interfaces,假设网卡名为eth33
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
auto ens33
iface ens33 inet static
address 192.168.2.138
netmask 255.255.255.0
gateway 192.168.2.1
dns-nameservers 192.168.2.1
c.配置DNS解析
vi /etc/NetworkManager/NetworkManager.conf --在[main]后追加dns=none
vi /etc/resolv.conf --设置DNS解析
nameserver 192.168.2.1
d.重启网卡
systemctl restart networking --Ubuntu/Debian:重启网络
systemctl status networking --Ubuntu/Debian:查看状态
e.auto与allow-hotplug区别
auto:不管有无网线,网卡都会启用,运行/etc/init.d/networking restart之后,网卡能自动重启
allow-hotplug:只会在开机时启动插网线的网卡,运行/etc/init.d/networking restart之后,网卡不能自动重启
DNS优先级:/etc/hosts文件 > /etc/network/interfaces中DNS > /etc/resolv.conf中DNS
修改主机名:/etc/hostname -> debian01
e.映射 vi /etc/hosts 或 C:\Windows\System32\drivers\etc\hosts
192.168.2.128 bigdata01
192.168.2.129 bigdata02
192.168.2.130 bigdata03
192.168.2.131 bigdata04
192.168.2.132 bigdata05
192.168.2.138 debian01
192.168.2.2 bigdata
03.开机设置三:配置root用户(图形界面)
a.配置一:root用户密码修改
sudo passwd root --修改root密码
su --切换root用户
sudo whoami --查看用户是否具有sudo权限
b.配置二:root用户登陆图像界面
vi /etc/gdm3/daemon.conf
AutomaticLoginEnable = true --以root自动登录
AutomaticLogin = root --以root自动登录
[security]
AllowRoot=true --允许root登录
c.配置三:root用户登陆图像界面
vi /etc/pam.d/gdm-autologin
auth required pam_success_if.so user!=root quiet_success --注释该行
d.配置四:root用户登陆图像界面
vi /etc/pam.d/gdm-password
auth required pam_success_if.so user!=root quiet_success --注释该行
e.配置五:root用户图形界面登陆错误
vi /root/.profile
tty -s && mesg n || true --修改内容
04.开机设置四:配置root用户(SSH界面)
a.安装openssh-server
yum list installed | grep openssh-server --检测是否安装
yum install openssh-server --如果未安装,则安装openssh-server
yum install -y glibc libgcc libstdc++ python ca-certificates tar openssh-server bash curl
b.配置
vi /etc/ssh/sshd_config
Port 22 --监听端口
ListenAddress 0.0.0.0 --监听地址
ListenAddress :: --监听地址
PermitRootLogin yes --开启远程访问(SSH,root用户登录)
--------------------------
PubkeyAuthentication yes --开启密钥验证(SSH,pubkey登录)
AuthorizedKeysFile .ssh/authorized_keys --开启密钥验证(SSH,pubkey登录)
--------------------------
PasswordAuthentication yes --开启密码验证(SSH,密码验证)
c.开启服务
systemctl start sshd --开启服务
systemctl enable sshd --开机自启
systemctl restart sshd --重启服务
ps -e | grep sshd --检查sshd服务是否已经开启
systemctl list-unit-files | grep sshd --检查sshd服务是否开机自启
yum check-update && yum install code -y --远程机器安装VScode
d.ssh免密钥登录(Remote-SSH只提供使用RSA秘钥远程登录,SSH不支持命令行-p输入明文密码)(默认aes256-cbc类型)
a.win10生成密钥
ssh-keygen -t rsa
b.将Win10中的公钥id_rsa.pub -> 手动放到Centos7中的authorized_keys
chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
c.win10远程访问(C:\Windows\System32\OpenSSH)
ssh [email protected]
ssh [email protected] -i "C:\Users\mysla\.ssh\id_rsa.ppk" -P 22
ssh [email protected] -i "C:\Users\mysla\.ssh\id_rsa.ppk" -P 22
d.putty远程访问(D:\software\Java\putty-0.74)
connection -> SSH -> Auth -> Browse -> 选中putty密钥(id_rsa.ppk)
session -> IP(192.168.2.128)、Port(22)、Saved(bigdata01) -> 连接
1.3 ubuntu
00.Ubuntu 24.04 LTS 是一个里程碑式的版本
a.系统与内核 (System & Kernel)
Linux Kernel: 6.8,带来了最新的硬件支持,并增强了性能调度与网络功能。
Systemd: 255,提供了更完善的系统和服务管理能力。
GNU C Library: 2.39,基础C库更新,提升了兼容性和安全性。
Netplan: 1.0,网络配置工具迎来重要更新,支持更复杂的网络场景。
b.编译器与工具链 (Compilers & Toolchain)
GCC: 14 (可选, 默认 13.2),提供了对最新C++标准的支持和更强的编译优化能力。
LLVM/Clang: 18
Python: 3.12,默认版本,带来了性能改进和新的语言特性。
Perl: 5.38
PHP: 8.3
Rustc: 1.75
Go: 1.22
OpenJDK: 21 (默认), 17, 11 可选,全面支持最新的Java LTS版本。
c.服务与数据库 (Services & Databases)
Apache: 2.4.58
Nginx: 1.24
MariaDB: 10.11
PostgreSQL: 16
Samba: 4.19
OpenSSH: 9.6p1,增强了安全性,默认禁用较弱的RSA/SHA1签名。
OpenSSL: 3.2
d.桌面环境与核心应用 (Desktop Environment & Core Applications)
GNOME: 46,带来了全局搜索的重大改进、更高效的文件管理、可变刷新率(VRR)的实验性支持以及优化的设置面板。
KDE Plasma: 5.27.11 (Kubuntu),Kubuntu 24.04 LTS 仍然使用 Plasma 5.27,以保证稳定性。
Installer: Subiquity,采用了全新的基于Flutter构建的桌面安装程序,支持如ZFS、自动安装等高级功能,界面更现代化。
App Center: 新的应用中心,替代了原有的 "Ubuntu Software",提供更流畅的Snap应用浏览和管理体验。
LibreOffice: 24.2
GIMP: 2.10.36
Inkscape: 1.3.2
01.开机设置一:安装
a.空白分区
此电脑 -> 管理 -> 磁盘管理 -> D盘 -> 压缩 -> 307200MB
b.手动分区,将EFI系统分区作为系统启动引导器
4096MB 逻辑分区 空间起始位置 EFI文件系统
32768MB 逻辑分区 空间起始位置 SWAP交换空间
4096MB 逻辑分区 空间起始位置 Ext4日志文件系统 /tmp
4096MB 逻辑分区 空间起始位置 Ext4日志文件系统 /boot
108544MB 逻辑分区 空间起始位置 Ext4日志文件系统 /home
153600MB 主分区 空间起始位置 Ext4日志文件系统 /
c.使用Ubuntu双系统
a.设置Bios
F2 -> Security -> Secure Boot -> Disabled --关闭安全防护
F2 -> Boot -> Legacy support -> Boot priority -> Windows --默认启动windows
b.切换系统
F12
d.关闭AOMEI OneKey Recovery
a.设置Bios
F2 -> Security -> Secure Boot -> Enabled --开启安全防护
F2 -> Boot -> Legacy support -> Boot priority -> Windows --默认启动windows
b.切换系统
F12
c.系统设置
msconfig -> 常规(选择性启动:加载系统服务、加载启动项)、引导(删除AOMEI OneKey Recovery)-> 应用
e.删除分区(Windows系统)
diskpart --进入分区命令
list disk --查看当前磁盘列表
select disk 0 --选中操作的磁盘
list partition --查看该磁盘下的分区
select partition X --选择操作的分区
delete partition override --强制删除该分区
f.安装Vmware Tools
tar -zxvf VMwareTools-10.0.0-2977863.tar.gz
sudo ./vmware-install.pl -y
g.常见的镜像源
http://mirrors.aliyun.com/ubuntu-releases/16.04/
http://mirrors.zju.edu.cn/ubuntu-releases/16.04/
http://mirrors.melbourne.co.uk/ubuntu-releases/
http://mirrors.ustc.edu.cn/ubuntu-releases/16.04/
02.开机设置二:配置root用户
a.配置一:root用户密码修改
sudo passwd root --修改root密码
su --切换root用户
sudo whoami --查看用户是否具有sudo权限
b.配置二:root用户登陆图像界面
gedit /usr/share/lightdm/lightdm.conf.d/50-ubuntu.conf
greeter-show-manual-login=true --追加内容
all-guest=false --追加内容
c.配置三:root用户登陆图像界面
gedit /etc/pam.d/gdm-autologin
auth required pam_success_if.so user!=root quiet_success --注释该行
d.配置四:root用户登陆图像界面
gedit /etc/pam.d/gdm-password
auth required pam_success_if.so user!=root quiet_success --注释该行
e.配置五:root用户图形界面登陆错误
gedit /root/.profile
tty -s && mesg n || true --修改内容
03.开机设置三:网卡
a.配置:卸载ideapad_laptop模块,启用无线网卡,打开文件权限
gedit /etc/modprobe.d/ideapad.conf
blacklist ideapad_laptop --追加内容
b.终端
sudo chmod 777 /etc/modprobe.d/ideapad.conf --打开文件权限
sudo modprobe -r ideapad_laptop --卸载ideapad模块
04.开机设置四:声卡
a.配置:root用户使用音频设备
gedit /etc/profile
pulseaudio --start --log-target=syslog --追加内容
b.终端
alsamixer -> HDA Intel PCH -> M --允许音频输出
05.开机设置五:显卡
a.配置:root用户亮度调节
gedit /etc/default/grub
quiet splash acpi_backlight=vendor acpi_osi=Linux --修改内容
b.终端
sudo update-grub --更新grub
06.开机设置六:进程
a.查看
ps -a --查看当前所有程序
top --查看当前活跃程序
q --返回终端
b.终止
kill [PID] --终止PID
kill 37788 --示例
pkill [ProcessName] --终止进程
pkill gnome-software --示例
killall [ProcessName] --终止程序所有实例
killall gedit --示例
c.snap
snap changes
sudo snap abort 7
07.开机设置七:更换数据源
a.配置文件
cd /etc/apt
cp sources.list sources.list.bak
vim sources.list
b.配置内容
deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
c.更新配置
sudo apt-get update
sudo apt-get upgrade
1.4 machine1
01.CUDA
a.禁止自带nouveau驱动
a.卸载已安装的nvidia驱动
sudo apt-get remove --purge nvidia*
sudo apt-get purge nvidia*
sudo apt-get autoremove
sudo ./NIVIDIA-Linux-X86_64-384.59.run --uninstall
b.禁用自带nouveau驱动
gedit /etc/modprobe.d/blacklist-nouveau.conf
blacklist nouveau
blacklist lbm-nouveau
options nouveau modeset=0
alias nouveau off
alias lbm-nouveau off
c.更新内核
sudo update-initramfs -u --更新内核
d.重启
reboot
e.测试
lsmod | grep nouveau
b.安装依赖
a.获取build-essential、 gcc-multilib、dkms
sudo apt-get install build-essential gcc-multilib dkms
sudo apt install make
sudo apt install gcc
sudo apt install g++
b.获取kernel source
apt-get install linux-source
apt-get install linux-headers-$(uname -r)
c.降低内核版本
uname -r
sudo apt-get remove linux-image-4.4.0-140-generic
sudo apt-get remove linux-image-$(uname -r)
d.内核相关命令
a.查看内核列表
sudo dpkg --get-selections |grep linux-image
b.查看当前使用的内核
uname -r
c.升级/安装内核
sudo apt-get install linux-image-4.4.0-75-generic
d.删除内核
sudo apt-get remove linux-image-4.4.0-75-generic
c.安装NVIDIA驱动
a.查看系统信息
lspci | grep -i nvidia --查看GPU型号
sudo dpkg --list | grep nvidia-* --查看NVIDIA驱动版本
lspci | grep -i vga --查看显卡型号
http://pci-ids.ucw.cz/mods/PC/10de?action=help?help=pci --电脑显卡型号:2191
nvidia-smi --具体显卡型号
nvcc -V --查看cuda版本
b.卸载已安装的nvidia驱动
sudo apt-get remove --purge nvidia*
c.关闭图形界面
sudo apt-get install lightdm
sudo service lightdm stop --停止服务
d.安装NVIDIA驱动
sudo chomd a+x NVIDIA-Linux-x86_64-430.09.run
sudo NVIDIA-Linux-x86_64-430.09.run -no-x-check -no-nouveau-check -no-opengl-files
-no-x-check:安装驱动时关闭X服务
-no-nouveau-check:安装驱动时禁用nouveau
-no-opengl-files:只安装驱动文件,不安装OpenGL文件
-Z, --disable-nouveau:禁用nouveau,此参数非必需,之前已经手动禁用nouveau
-A:查看更多高级选项
e.安装过程中一些选项
The distribution-provided pre-install script failed! Are you sure you want to continue? 选择 yes 继续
Would you like to register the kernel module souces with DKMS? This will allow DKMS to automatically build a new module, if you install a different kernel later? 选择 No 继续
Nvidia's 32-bit compatibility libraries? 选择 No 继续
Would you like to run the nvidia-xconfigutility to automatically update your x configuration so that the NVIDIA x driver will be used when you restart x? Any pre-existing x confile will be backed up. 选择Yes 继续
f.挂载Nvidia驱动
modprobe nvidia
g.重启图形界面
sudo service lightdm start --开启服务
h.验证驱动是否安装成功
nvidia-smi
nvidia-settings
d.安装CUDA9.0
a.关闭图形界面
sudo service lightdm stop --停止服务
b.安装CUDA9.0
sudo chmod a+x cuda_9.0.176_384.81_linux.run
sudo ./cuda_9.0.176_384.81_linux.run --no-opengl-libs
--no-opengl-libs:只安装驱动文件,不安装OpenGL文件,必需参数,注意不是-no-opengl-files
c.安装过程中一些选项
阅读声明:一直按D,然后Accept
选项install nvidia accelerated Graphics Driver:选择N(已安装了NVIDIA驱动)
选项install the OpenGL libraries:选择N(双显卡),选择Y(单显卡)
后面选项:都可以选择Y
最后一个选项:选择N(不复制Samples,因为安装目录下有samples)
Driver :Installed
Toolkit :Installed in /usr/local/cuda-9.0
Samples :Installed in /home/vincent
d.环境变量
export CUDA_HOME=/usr/local/cuda-9.0
export LD_LIBRARY_PATH=/usr/local/cuda-9.0/lib64:$LD_LIBRARY_PATH
export PATH=/usr/local/cuda-9.0/bin:$PATH
e.重启图形界面
sudo service lightdm start --开启服务
f.验证cuda是否安装成功
nvcc -V
g.两个测试均为Result = PASS,说明CUDA安装成功
cd /usr/local/cuda-9.0/samples/1_Utilities/deviceQuery --测试1:编译并测试设备 deviceQuery
sudo make
./deviceQuery
cd ../bandwidthTest --测试2:编译并测试带宽 bandwidthTest
sudo make
./bandwidthTest
h.若上述测试不通过,则有有可能是缺少依赖
sudo apt-get install freeglut3-dev \
build-essential \
libx11-dev \
libxmu-dev \
libxi-dev \
libgl1-mesa-glx \
libglu1-mesa \
libglu1-mesa-dev
i.重启
重启黑屏,在grub界面进入linux的选择上按e键,找到quiet splash,在后面加nouveau.modeset=0,然后按F10启动
j.卸载
sudo /usr/local/cuda-9.2/bin/uninstall_cuda-9.2.pl --卸载CUDA
sudo /usr/bin/nvidia-uninstall --卸载NVIDIA
e.安装CUDNN7.0.5
a.安装:Debian File形式
sudo dpkg -i libcudnn7_7.0.5.15-1+cuda9.0_amd64.deb
sudo dpkg -i libcudnn7-dev_7.0.5.15-1+cuda9.0_amd64.deb
sudo dpkg -i libcudnn7-doc_7.0.5.15-1+cuda9.0_amd64.deb
b.安装:Tar File形式
tar -xzvf cudnn-9.0-linux-x64-v7.tgz
sudo cp cuda/include/cudnn.h /usr/local/cuda/include
sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64
sudo chmod a+r /usr/local/cuda/include/cudnn.h
sudo chmod a+r /usr/local/cuda/lib64/libcudnn*
c.验证Debian File形式,在/usr/src/cudnn_samples_v7有一些cudnn示例,编译mnistCUDNN sample进行验证
cp -r /usr/src/cudnn_samples_v7/ $HOME
cd $HOME/cudnn_samples_v7/mnistCUDNN
make clean && make
./mnistCUDNN
d.验证CUDNN是否安装成功
cat /usr/local/cuda/version.txt
cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MAJOR -A 2
f.其他方式
a.方式一:使用标准Ubuntu仓库进行自动安装
sudo apt-get update
sudo ubuntu-drivers devices --显示可安装NVIDIA驱动
sudo ubuntu-drivers autoinstall --安装
b.方式二:使用图形驱动程序PPA存储库安装NVIDIA beta驱动程序
sudo add-apt-repository ppa:graphics-drivers/ppa --添加ppa库到系统中
sudo apt-get update --更新
sudo ubuntu-drivers devices --显示可安装NVIDIA驱动
sudo apt-get install nvidia-xxx --xxx代表版本号
02.Anaconda
a.安装Anaconda3
sh /Ubuntu/software/JetBrains/Anaconda3/Anaconda3-2019.10-Linux-x86_64.sh
[/root/anaconda3] >>> /usr/local/anaconda3
mv /Ubuntu/software/JetBrains/Anaconda3/.condarc /root/.condarc
mkdir /root/pip
mv /Ubuntu/software/JetBrains/Anaconda3/pip/pip.ini /root/pip/pip.ini
b.环境变量
gedit /root/.bashrc
export PATH=$PATH:/usr/local/anaconda3/bin
source /root/.bashrc
c.conda测试
a.命令
conda info
conda info --envs
conda create -n tf2 tensorflow-gpu python=3.6
conda activate tf2
conda deactivate
conda remove -n tf2 --all
conda install scipy
conda remove scipy
conda list
conda --version
conda update -n base -c defaults conda
b.镜像源(/root/.condarc)
channels:
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/menpo/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/bioconda/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
show_channel_urls: true
ssl_verify: true
c.查看配置信息
conda info
d.python测试
a.命令
pip3 --version
pip3 install --upgrade pip
python3 --version
python3 -m site
python3 -m site -help
pip freeze > requirements.txt
pip install -r requirements.txt
pip unistall -r requirements.txt
https://pypi.tuna.tsinghua.edu.cn/simple
b.镜像源(/root/pip/pip.ini)
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple/
c.修改pip默认下载位置(/usr/lib/python3.6/site.py,第87行附近)
USER_SITE = "/root/.local"
USER_BASE = "/root/.local/lib/python3.6/site-packages"
d.查看配置信息
python3 -m site
e.快捷方式
a.创建anaconda.desktop
gedit /usr/share/applications/anaconda.desktop
b.编辑anaconda.desktop
[Desktop Entry]
Version=1.0
Name=Anaconda
Type=Application
GenericName=Anaconda
Comment=Scientific Python Development Environment - Python3
Categories=Development;Science;IDE;Qt;Education;
Exec=/usr/local/anaconda3/bin/anaconda-navigator
Icon=/usr/local/anaconda3/lib/python3.7/site-packages/anaconda_navigator/static/images/anaconda-icon-256x256.png
Terminal=false
StartupNotify=true
MimeType=text/x-python;
03.Pytorch 1.2.0
a.创建Pytorch新环境,并指定python版本为3.7.9
conda create -n pytorch python=3.7.9
b.列举conda当前全部环境
conda env list
c.激活Pytorch新环境
conda activate pytorch
d.安装Pytorch(conda方式,可以判断所有安装包的版本间的兼容性,各种必备包自动安装),管理员方式启动
a.升级conda
conda update -n base -c defaults conda
b.安装Pytorch的GPU版本(注意一定去掉-c pytorch,才可以使用国内镜像加速)
conda install pytorch==1.2.0 torchvision==0.4.0 cudatoolkit=10.0
c.安装Pytorch的CPU版本
conda install pytorch torchvision cpuonly
e.测试Pytorch
import torch
print(torch.__version__)
print('gpu:', torch.cuda.is_available())
04.TensorFlow 2.0.0
a.创建TensorFlow新环境,并指定python版本为3.7.9
conda create -n tf2 tensorflow-gpu python=3.7.9
b.列举conda当前全部环境
conda env list
c.激活TensorFlow新环境
conda activate tf2
d.安装TensorFlow(conda方式,可以判断所有安装包的版本间的兼容性,各种必备包自动安装),管理员方式启动
a.升级conda
conda update -n base -c defaults conda
b.安装TensorFlow的GPU版本
conda search tensorflow-gpu
conda install tensorflow-gpu=2.0.0
c.安装TensorFlow的CPU版本
conda search tensorflow
conda install tensorflow=2.0.0
e.测试TensorFlow
import tensorflow as tf
tf.compat.v1.disable_eager_execution()
sess = tf.compat.v1.Session()
a=tf.constant(1)
b=tf.constant(2)
print(sess.run(a+b))
print(tf.test.is_gpu_available())
f.解决报错
pip uninstall tensorflow
pip install tensorflow==2.0.0
g.tensorflow-gpu==1.8.0只支持gcc4.9
a.报错:
软件包gcc还没有可供安装的候选者
b.解决
a.添加源
sudo gedit /etc/apt/sources.list
deb http://dk.archive.ubuntu.com/ubuntu/ xenial main
deb http://dk.archive.ubuntu.com/ubuntu/ xenial universe
b.更新源
sudo apt update
c.安装
sudo apt install g++-4.9
sudo apt install gcc-4.9
c.用update-alternatives来为整个系统更改gcc版本
a.设置优先级
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 40
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 55
update-alternatives --install /usr/bin/gcc gcc /usr/local/bin/gcc 54
b.列出可用的gcc替代版本
update-alternatives --list gcc
c.选择可用的Python替代版本
update-alternatives --config gcc
d.查看版本
gcc -v
05.Jupyter Notebook
a.常见错误
a.命令
jupyter notebook --generate-config
b.报错
ImportError: DLL load failed: 找不到指定的模块
ModuleNotFoundError: No module named 'pysqlite2'
c.解决
https://www.pianshen.com/article/56211259074/
去sqlite3官网下载对应64位的插件,将sqlite3.def、sqlite3.dll复制到../Anaconda/DLLs目录
b.默认路径
a.打开文件
gedit /root/.jupyter/jupyter_notebook_config.py
b.修改jupyter_notebook_config.py
## The directory to use for notebooks and kernels.
c.NotebookApp.notebook_dir = '/Ubuntu/software_ware/workspace_conda'
c.运行
jupyter notebook --allow-root
1.5 machine2
01.常见工具
a.VScode
sudo dpkg -i /Ubuntu/software/JetBrains/VScode/code_1.50.1-1602600906_amd64.deb
b.Chorme
sudo dpkg -i /Ubuntu/document/Office/Chorme/google-chrome-stable_current_amd64.deb
c.CloudMusic
sudo dpkg -i /Ubuntu/document/CloudMusic/netease-cloud-music_1.2.1_amd64_ubuntu_20190428.deb
d.QQ
sudo dpkg -i /Ubuntu/document/Tencent/QQ/linuxqq_2.0.0-b2-1084_amd64.deb
e.software
electronic-wechat
Telegram Desktop
Gnome Tweaks
09.搜狗输入法
a.安装
sogoupinyin_2.3.2.07_amd64-831.deb
b.卸载
Language Support -> fcitx修改为IBus --修改输入法
sudo dpkg -l sog* --查找
sudo dpkg -P sogoupinyin --卸载
sudo apt-get purge fcitx --彻底删除fcitx
sudo apt-get autoremove --删除多余的依赖
10.火狐浏览器
a.安装国内版
tar jxvf Firefox-latest-x86_64.tar.bz2
cd Firefox-latest-x86_64
sudo mv firefox /usr/lib/
b.快捷方式
gedit /usr/share/applications/firefox.desktop
[Desktop Entry]
Name=firefox
Name[zh_CN]=火狐浏览器
Comment=火狐浏览器
Exec=/usr/lib/firefox/firefox
Icon=/usr/lib/firefox/browser/chrome/icons/default/default128.png
Terminal=false
Type=Application
Categories=Appliction;
Encoding=UTF-8
StartupNotify=true
d.Flash
tar -zxvf flash_player_npapi_linux.x86_64.tar.gz
mv libflashplayer.so /usr/lib/mozilla/plugins
chmod 777 /usr/lib/mozilla/plugins/libflashplayer.so
11.Typora
a.下载
wget -qO - https://typora.io/linux/public-key.asc | sudo apt-key add -
b.仓库
sudo add-apt-repository 'deb https://typora.io/linux ./'
sudo apt-get update
c.安装
sudo apt-get install typora
d.图标
usr/share/application -> Typora -> 属性 -> 命令:Exec=typora %U --no-sandbox
e.解压
/Ubuntu/document/Office/Typora
tar -zxvf Typora-linux-x64.tar.gz
cd Typora-linux-x64
mv /bin/Typora-linux-x64 /usr/local
f.创建pycharm.desktop
gedit /usr/share/applications/Typora.desktop
g.编辑pycharm.desktop
[Desktop Entry]
Name=Typora
GenericName=Editorubuntu / linux
Comment=Typroa - a markdown editor
Exec="/usr/local/Typora-linux-x64/Typora" %U --no-sandbox
Icon=/usr/local/Typora-linux-x64/resources/app/asserts/icon/icon_256x256.png
Terminal=false
Categories=Markdown;ux
StartupNotify=false
Type=Application
12.宝塔面板
a.升级openssl版本为1.1.1
cd /Ubuntu/software/Linux/BaoTa/
tar -zxvf openssl-1.1.1g.tar.gz
cd openssl-1.1.1g
./config
make && make install
echo "export LD_LIBRARY_PATH=/usr/local/lib" >> ~/.bashrc --添加环境
export LD_LIBRARY_PATH=/usr/local/lib --添加环境
openssl version --查看版本
b.安装
wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh f2dec8
c.登录
外网面板地址: http://192.168.3.102:8888/9a6bf9a9
内网面板地址: http://192.168.3.102:8888/9a6bf9a9
username: myslayers
password: XXXXXXXX
d.设置
bt
/etc/init.d/bt default
13.Pycharm
a.安装
cd /Ubuntu/software/JetBrains/Pycharm/
tar -zxvf pycharm-professional-2019.2.6.tar.gz
mv pycharm-2019.2.6 /usr/local/pycharm
b.环境变量
gedit /root/.bashrc
export PATH=$PATH:/usr/local/pycharm/bin
source /root/.bashrc
c.快捷方式
a.创建pycharm.desktop
gedit /usr/share/applications/pycharm.desktop
b.编辑pycharm.desktop
[Desktop Entry]
Version=1.0
Type=Application
Name=PyCharm
Icon=/usr/local/pycharm/bin/pycharm.svg
Exec=sh /usr/local/pycharm/bin/pycharm.sh
MimeType=application/x-py;
Name[en_US]=pycharm
14.IntelliJ IDEA
a.安装
cd /Ubuntu/software/JetBrains/IDEA
tar -zxvf ideaIU-2019.3.5.tar.gz
mv idea-IU-193.7288.26 /usr/local/idea
b.环境变量
gedit /root/.bashrc
export PATH=$PATH:/usr/local/idea/bin
source /root/.bashrc
c.快捷方式
a.创建idea.desktop
gedit /usr/share/applications/idea.desktop
b.编辑idea.desktop
[Desktop Entry]
Version=1.0
Type=Application
Name=IntelliJ IDEA
Icon=/usr/local/idea/bin/idea.svg
Exec=sh /usr/local/idea/bin/idea.sh
MimeType=application/x-py;
Name[en_US]=IntelliJ IDEA
15.WebStorm
a.安装
cd /Ubuntu/software/JetBrains/WebStorm
tar -zxvf WebStorm-2019.3.5.tar.gz
mv WebStorm-193.7288.28 /usr/local/webstorm
b.环境变量
gedit /root/.bashrc
export PATH=$PATH:/usr/local/webstorm/bin
source /root/.bashrc
c.快捷方式
a.创建webstorm.desktop
gedit /usr/share/applications/webstorm.desktop
b.编辑webstorm.desktop
[Desktop Entry]
Version=1.0
Type=Application
Name=WebStorm
Icon=/usr/local/webstorm/bin/webstorm.svg
Exec=sh /usr/local/webstorm/bin/webstorm.sh
MimeType=application/x-py;
Name[en_US]=WebStorm
16.Datagrip
a.安装
cd /Ubuntu/software/JetBrains/Datagrip
tar -zxvf datagrip-2019.3.5.tar.gz
mv DataGrip-2019.3.5 /usr/local/datagrip
b.环境变量
gedit /root/.bashrc
export PATH=$PATH:/usr/local/datagrip/bin
source /root/.bashrc
c.快捷方式
a.创建datagrip.desktop
gedit /usr/share/applications/datagrip.desktop
b.编辑datagrip.desktop
[Desktop Entry]
Version=1.0
Type=Application
Name=Datagrip
Icon=/usr/local/datagrip/bin/datagrip.svg
Exec=sh /usr/local/datagrip/bin/datagrip.sh
MimeType=application/x-py;
Name[en_US]=Datagrip
2 mysql
2.1 bio
01.常用信息1
a.db4free,替代sqlite
db4free.net - 免费的 MySQL 数据库
只提供MySQL服务
提供服务:基本最新版Mysql8.0服务
服务器地址:国外
优点:
1、无需注册,直接用邮箱申请
2、用户名称和密码可以自定义
缺点:
1、一个邮箱账号,只能绑定一个账号
2、不定期重置仓库大小超过200MB的仓库数据
b.sqlpub
SQLPub - 免费的MySQL数据库
只提供MySQL服务
提供服务:最新版Mysql8.0服务;最大36000次/小时的请求、同时30个连接和500M存储空间
服务器地址:国内
优点:
1、无需注册,直接用邮箱申请
2、仓库空间比较大
缺点:
1、一个邮箱账号,只能绑定一个账号
2、密码自动生成,比较复杂
c.ElephantSQL
ElephantSQL - PostgreSQL as a Service
提供PostgreSQL服务
服务器地址:由国内地址
提供服务:20MB免费
d.MongoDB Cloud
提供MongoDB数据库服务
服务器地址:有国内
提供服务:永久512MB免费
优点:
1、空间大且永久免费
2、有国内服务器地址
e.Redis Cloud
提供Redis服务
02.常用信息2
a.SVNCloud
专业SVN服务,代码托管,数据库托管,MYSQL服务(wsfdb.cn)
只提供MySQL服务
提供服务(免费版本):Mysql7.x;永久5MB(免费),可以升级vip扩展(存储容量);支持:在线备份、备份下载、导入备份、修改密码、实时开通、自动清理日志
服务器地址:国内
优点:
1、一个账号,可以无限创建仓库
2、用户名和密码可以自定义(用户名和仓库名一样)
缺点:
需要注册账号使用
注:这个公司同时提供svn云服务,免费的有80MB,同样不限制创建数量
b.MemFireDB
只提供PostgreSQL服务
服务器地址:国内
缺点:一个账号只能注册一个
c.Heroku
Cloud Application Platform | Heroku
提供PostgreSQL服务
服务器地址:国外
提供服务:1w行数据(小的可怜)
优点:可创建多个数据库
缺点:空间小、连接速度慢
d.RabbitMQ
CloudAMQP - Queue starts here.
提供RabbitMQ服务
-----------------------------------------------------------------------------------------------------
Little Lemur - For Development
Max 100 queues
Max 10 000 queued messages
Max idle queue time 28 days
e.Kafka
CloudKarafka
Apache Kafka Message streaming as a Service
提供Kafka服务
-----------------------------------------------------------------------------------------------------
付费
03.常用信息3
a.地区
US East (N. Virginia) - 美国东部(北弗吉尼亚)
US East (Ohio) - 美国东部(俄亥俄)
US West (Oregon) - 美国西部(俄勒冈)
2.2 mock
01.windows
a.Node
a.环境变量
NODE_HOME:D:\software\JavaScript\Nodejs
path:%NODE_HOME%
%NOED_HOME%\node_modules
D:\software\Repository\Repository_Npm
b.测试
node -v
c.配置
npm config set prefix "D:\software\Repository\Repository_Npm" --设置本地仓库
npm config set cache "D:\software\Repository\Repository_Npm_Cache" --设置缓存位置
npm config ls --查看是否修改成功
b.MongoDB
a.环境变量
MongoDB_HOME:D:\software\SQL\MongoDB
path:%MongoDB_HOME%\bin
b.测试
mongod --dbpath=D:\software_ware\workspace_mongo\data --port=27017 --logpath=D:\software_ware\workspace_mongo\log\mongo.log --install --serviceName "MongoDB"
net start MongoDB --启动服务
mongo --启动
c.Redis
a.环境变量
Redis_HOME:D:\software\SQL\Redis
path:%Redis_HOME%
b.测试
redis-server.exe redis.windows.conf --服务端
redis-cli.exe -h 127.0.0.1 -p 6379 --客户端
d.Easymock
a.下载git
yum install -y git
b.克隆项目
git clone https://github.com/easy-mock/easy-mock.git
c.安装npm
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install(如果无法使用npm,刷新环境变量source /etc/profile)
d.启动
npm run dev
e.测试
http://127.0.0.1:7300
f.部署阶段
a.编译easy-mock文件
npm run build
b.启动
pm2 start app.js -i 4 -n Easymock --启动
pm2 save --保存NodeJS服务
pm2 list --查看列表
pm2 startup --创建开机启动
127.0.0.1:7300 --访问
02.linux
a.nodejs
a.下载
wget https://nodejs.org/dist/v8.9.1/node-v8.9.1-linux-x64.tar.xz
b.解压
tar -xvJf node-v8.9.1-linux-x64.tar.xz
c.重命名
mv node-v8.9.1-linux-x64 node
d.配置环境变量
vi /etc/profile
export PATH=$JAVA_HOME/bin:/apps/node/bin:/apps/mongodb/bin:$PATH
source /etc/profile
b.MongoDB
a.下载
curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.4.tgz
b.解压
tar -zxvf mongodb-linux-x86_64-3.6.4.tgz
c.重命名
mv mongodb-linux-x86_64-3.6.4 mongodb
d.配置环境变量
vi /etc/profile
export PATH=$JAVA_HOME/bin:/apps/node/bin:/apps/mongodb/bin:$PATH
source /etc/profile
e.配置存储数据、日志
cd mongodb/
mkdir data
touch logs
f.启动
bin/mongod --dbpath=/apps/mongodb/data --logpath=/apps/mongodb/logs --port=27017 &
c.redis
a.下载
wget http://download.redis.io/releases/redis-4.0.0.tar.gz
b.解压
tar -zxvf redis-4.0.0.tar.gz
c.重命名
mv redis-4.0.0 redis
d.编译
cd redis/
yum install gcc-c++
make MALLOC=libc
e.配置redis.conf
daemonize yes
f.启动
src/redis-server redis.conf &
src/redis-cli -p 6379
d.easymock
a.下载git
yum install -y git
b.克隆项目
git clone https://github.com/easy-mock/easy-mock.git
c.安装npm
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install(如果无法使用npm,刷新环境变量source /etc/profile)
d.启动
npm run dev
e.测试
http://192.168.2.128:7300
2.3 yearning
01.下载
http://yearning.io/
02.配置
[Mysql]
Db = "Yearning"
Host = "127.0.0.1"
Port = "3306"
Password = "xxxx"
User = "root"
[General] #数据库加解密key,只可更改一次。
SecretKey = "dbcjqheupqjsuwsm"
03.初始化数据结构
./Yearning -m
04.启动
./Yearning -s
05.测试
192.168.2.128:8000
admin / Yearning_admin
2.4 activemq
01.下载
wget https://mirrors.tuna.tsinghua.edu.cn/apache/activemq/5.15.13/apache-activemq-5.15.13-bin.tar.gz
tar -zxvf apache-activemq-5.15.13-bin.tar.gz
02.启动
cd apache-activemq-5.15.13
bin/activemq start
03.测试
192.168.2.128:8161 --测试(用户名:admin 密码:admin)
2.5 rabbitmq
01.安装erlang
a.安装依赖
yum -y install gcc glibc-devel make ncurses-devel openssl-devel xmlto perl wget gtk2-devel binutils-devel
b.下载
wget http://erlang.org/download/otp_src_22.0.tar.gz
http://file.zhaobl.com/common/otp_src_22.0.tar.gz --速度过慢,切换地址直接下载
c.解压
tar -zxvf otp_src_22.0.tar.gz
d.移走
mv otp_src_22.0 /usr/local/
e.切换目录
cd /usr/local/otp_src_22.0/
f.创建即将安装的目录
mkdir ../erlang
g.配置安装路径
./configure --prefix=/usr/local/erlang
h.安装
make install
i.查看是否安装成功
ll /usr/local/erlang/bin
j.添加环境变量
echo 'export PATH=$PATH:/usr/local/erlang/bin' >> /etc/profile
k.刷新环境变量
source /etc/profile
l.测试命令
erl
02.安装RabbitMQ
a.下载
wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.15/rabbitmq-server-generic-unix-3.7.15.tar.xz
b.解压
yum install -y xz --解压tar.xz格式
/bin/xz -d rabbitmq-server-generic-unix-3.7.15.tar.xz --第一次解压
tar -xvf rabbitmq-server-generic-unix-3.7.15.tar --第二次解压
c.移走
mv rabbitmq_server-3.7.15/ /usr/local/
d.改名
mv /usr/local/rabbitmq_server-3.7.15 rabbitmq
e.配置环境变量
echo 'export PATH=$PATH:/usr/local/rabbitmq/sbin' >> /etc/profile
f.刷新环境变量
source /etc/profile
g.创建配置目录
mkdir /etc/rabbitmq
h.启动命令
rabbitmq-server -detached --启动
rabbitmqctl stop --停止
rabbitmqctl status --状态
i.WEB管理
rabbitmq-plugins enable rabbitmq_management --开启WEB插件
http://127.0.0.1:15672/ --用户名guest、密码guest
j.用户管理
rabbitmqctl list_users --查看所有用户
rabbitmqctl add_user myslayers 4023615 --添加一个用户
rabbitmqctl set_permissions -p "/" zhaobl ".*" ".*" ".*" --配置权限
rabbitmqctl list_user_permissions myslayers --查看用户权限
rabbitmqctl set_user_tags zhaobl administrator --设置tag
rabbitmqctl delete_user guest --删除用户
2.6 mysql-5.5.58
01.清理Centos7自带mariadb
rpm -qa |grep -i mysql
rpm -qa |grep -i mariadb
yum remove mariadb-libs-5.5.56-2.el7.x86_64
02.rpm安装MySQL
a.安装
rpm -ivh MySQL-server-5.5.58-1.el6.x86_64.rpm --force --nodeps
rpm -ivh MySQL-client-5.5.58-1.el6.x86_64.rpm --force --nodeps
b.验证
mysqladmin --version
03.配置MySQL
a.启动MySQL服务
service mysql start
b.查看MySQL状态
service mysql status
c.设置密码
/usr/bin/mysqladmin -u root password root
d.登录MySQL
mysql -uroot -p
e.开启MySQL远程访问
mysql> grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option;
mysql> flush privileges;
mysql> exit
f.Windows远程访问
mysql -uroot -proot -h192.168.2.128 -P3306
04.常见命令
a.启动命令
service mysql start
b.关闭命令
service mysql stop
c.重启命令
service mysql restart
d.查看服务状态
service mysql status
e.查看MySQL系统配置
cat /etc/my.cnf
05.MySQL服务:常见报错/var/lib/mysql/mysql.sock不存在
a.手动启动服务
/etc/init.d/mysql start
b.开机自启
chkconfig mysql on
c.关闭开机自启
chkconfig mysql off
d.检查开机自启
ntsysv
2.7 mysql-5.7.17
01.清理Centos7自带mariadb
rpm -qa |grep -i mysql
rpm -qa |grep -i mariadb
yum remove mariadb-libs-5.5.56-2.el7.x86_64
02.安装MySQL
a.下载
wget http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm
b.解压
rpm -ivh mysql57-community-release-el7-10.noarch.rpm
c.安装
yum install mysql-community-server
03.修改密码
a.启动MySQL服务
systemctl start mysqld.service
b.查看MySQL状态
systemctl status mysqld.service
c.从日志中获取临时密码
grep "password" /var/log/mysqld.log
d.登录MySQL
mysql -uroot -p
e.修改密码
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
04.远程访问
a.开启MySQL远程访问
mysql> grant all privileges on *.* to 'root'@'%' identified by '123456' with grant option;
mysql> flush privileges;
mysql> exit;
b.firewalld添加开放端口
firewall-cmd --zone=public --add-port=3306/tcp --permanent --mysql端口3306
firewall-cmd --zone=public --add-port=8080/tcp --permanent --Tomcat端口8080
firewall-cmd --reload --重启防火墙
systemctl stop firewalld --关闭防火墙
systemctl disable firewalld --禁止开机自启
c.远程cmd登录MySQL
mysql -uroot -proot -h192.168.2.128 -P3306 -Dtest
mysql -u用户名 -p密码 -h远程数据库IP地址 -P端口 -D数据库名(可以不用指定具体的数据库名)
05.修改编码
a.查看字符编码
mysql> status
mysql> show variables like '%char%' ;
b.修改配置文件,vi /etc/my.cnf
[client] --添加第一行
default-character-set=utf8 --添加第二行
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
character-set-server=utf8 --添加第三行
collation-server=utf8_general_ci --添加第四行
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
c.保存更改后的my.cnf文件后,重启下mysql
systemctl restart mysqld.service
06.创建新的MySQL用户,并授权
a.创建用户
create user 'testuser'@'%' identified with mysql_native_password by '123456';
b.授权
grant all privileges on *.* to 'testuser'@'%' with grant option;
c.修改密码过期规则
alter user 'testuser'@'%' identified by '123456' password expire never;
d.立即生效
flush privileges;
07.binlog功能
a.修改配置文件,vi /etc/my.cnf
[client]
default-character-set=utf8
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
character-set-server=utf8
collation-server=utf8_general_ci
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
log-bin=mysql-bin --文件目录
binlog-format=ROW --选择row模式
server_id=1 --canal和slaveId不重复
b.验证是否开启
show master logs; --查看所有日志文件
show master status; --查看正在写入的日志文件
show binlog events; --查看当前binlog文件内容
show binlog events in 'my-bin.000001'; --指定日志文件查看
flush logs; --结束正在写入日志文件
reset master; --删除所有日志,重新记录
c.二进制日志文件导出
mysqlbinlog binlog.000001 >1.sql --导出为sql格式
mysqlbinlog --start-datetime="2018-03-20 11:25:56" --stop-datetime="2018-03-20 14:20:10" mysql-bin.000001 > /data/test01.log --按时间点导出
mysqlbinlog --start-position=5786 --stop-position=6254 mysql-bin.000001 > /data/test02.log --按事件位置导出
08.如何确定MySQL服务已经启动?
a.chkconfig命令
chkconfig --list
b.查询端口
netstat -tulpn
c.查询进程
ps -ef | grep mysqld
ps -ef | grep mysqld_safe
09.MySQL服务:常见报错/var/lib/mysql/mysql.sock不存在
a.手动启动服务
/etc/init.d/mysqld start
b.开机自启
systemctl enable mysqld.service
c.关闭开机自启
systemctl disable mysqld.service
d.检查开机自启
ntsysv
10.彻底卸载MySQL
a.查看是否有安装的MySQL:
rpm -qa | grep -i mysql
yum list install mysql*
b.卸载MySQL安装包
yum remove mysql mysql-server mysql-libs compat-mysql51
yum remove mysql-community-release、
rpm -e --nodeps mysql-community-libs-5.7.22-1.el7.x86_64
rpm -e –nodeps mysql57-community-release-el7-11.noarch
c.删除残留的MySQL目录或文件
i.残留的MySQL目录
whereis mysql
ii.残留的MySQL文件
find / -name mysql
iii.删除
rm -rf xxx
d.删除MySQL配置文件
rm –rf /usr/my.cnf
rm -rf /root/.mysql_sercret
e.删除MySQL开机自启服务
chkconfig --list | grep -i mysql
chkconfig --del mysqld
11.免密码登录MySQL
a.停止MySQL服务
systemctl stop mysqld.service
b.以不检查权限的方式启动mysqld,root身份运行
mysqld --user=root --skip-grant-tables &
c.免密码登录MySQL
mysql -u root
d.设置密码
UPDATE mysql.user SET authentication_string=PASSWORD('密码') where USER='root';
ALTER USER 'root'@'localhost' IDENTIFIED BY '密码';
SET PASSWORD FOR root=PASSWORD('密码');
12.数据库存放目录
a.数据库目录
datadir=/var/lib/mysql
b.pid文件目录
pid-file=/var/lib/mysql/bigdata01.pid
c.MySQL核心目录
/var/lib/mysql 安装目录
/usr/share/mysql 配置文件
/usr/bin 命令目录(mysqladmin、mysqldump等)
/etc/init.d/mysql 启停脚本
d.MySQL配置文件
my-huge.cnf 高端服务器 1-2G内存
my-large.cnf 中等规模
my-medium.cnf 一般
my-small.cnf 较小
但是,以上配置文件mysql默认不能识别,默认只能识别 /etc/my.cnf
若采用 my-huge.cnf,通过命令:#cp /usr/share/mysql/my-huge.cnf /etc/my.cnf
e.注意
MySQL5.5:默认配置文件/etc/my.cnf
MySQL5.6:默认配置文件/etc/mysql-default.cnf
2.8 mysql-8.0.21
01.清理Centos7自带mariadb
rpm -qa |grep -i mysql
rpm -qa |grep -i mariadb
yum remove mariadb-libs-5.5.56-2.el7.x86_64
02.安装MySQL
a.下载
wget https://dev.mysql.com/downloads/file/?id=496950
b.解压
tar -xvf mysql-8.0.21-1.el7.x86_64.rpm-bundle.tar
c.依次安装common、libs、client、server
rpm -ivh mysql-community-common-8.0.21-1.el7.x86_64.rpm --force --nodeps
rpm -ivh mysql-community-libs-8.0.21-1.el7.x86_64.rpm --force --nodeps
rpm -ivh mysql-community-client-8.0.21-1.el7.x86_64.rpm --force --nodeps
rpm -ivh mysql-community-server-8.0.21-1.el7.x86_64.rpm --force --nodeps
d.验证
mysqladmin --version
03.修改密码
a.用户授权:初始化时,如果不存在,会创建它;如果存在,而且该目录里有数据,会报错并终止初始化
vi /etc/my.cnf
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
chmod -R 777 /var/lib/mysql --文件权限
rm -rf /var/lib/mysql/* --删除文件,防止报错
b.初始化数据
mysqld --initialize
c.开启服务
systemctl start mysqld.service
d.启用数据
systemctl enable mysqld
e.从日志中获取临时密码
grep "password" /var/log/mysqld.log
f.登录MySQL
mysql -uroot -p
g.修改密码
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456';
04.远程访问
a.开启MySQL远程访问
mysql> use mysql;
mysql> select host, user, authentication_string, plugin from user;
mysql> update user set host='%' where user='root';
mysql> flush privileges;
mysql> exit;
b.firewalld添加开放端口
firewall-cmd --zone=public --add-port=3306/tcp --permanent --mysql端口3306
firewall-cmd --zone=public --add-port=8080/tcp --permanent --Tomcat端口8080
firewall-cmd --reload --重启防火墙
systemctl stop firewalld --关闭防火墙
systemctl disable firewalld --禁止开机自启
c.远程cmd登录MySQL
mysql -uroot -proot -h192.168.2.128 -P3306 -Dtest
mysql -u用户名 -p密码 -h远程数据库IP地址 -P端口 -D数据库名(可以不用指定具体的数据库名)
3 fastdfs
3.1 tracker
01.gcc环境
yum install gcc-c++
02.下载Tracker依赖库 -> libevent库
yum -y install libevent
03.下载Tracker依赖库 -> libfastcommon库
a.下载
cd /usr/local
wget https://github.com/happyfish100/libfastcommon/archive/V1.0.43.tar.gz
tar -zxvf libfastcommon-1.0.43.tar.gz
b.编译
cd /usr/local/libfastcommon-1.0.43/
./make.sh
./make.sh install
04.安装Tracker
a.下载
cd /usr/local
https://github.com/happyfish100/fastdfs/archive/V6.06.tar.gz
tar -zxvf fastdfs-6.06.tar.gz
b.编译
cd /usr/local/fastdfs-6.06/
./make.sh
./make.sh install
c.将conf目录下的配置文件拷贝到/etc/fdfs目录下
cd /usr/local/fastdfs-6.06/conf/
cp ./* /etc/fdfs/
d.配置tracker.conf
mkdir /home/myslayers/fastdfs --创建元数据存储目录
vi /etc/fdfs/tracker.conf --打开tracker.conf
port = 22122 --默认端口
base_path = /home/myslayers/fastdfs --元数据存储目录必须存在
e.启动
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf start --启动Tracker
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf stop --关闭Tracker
3.2 storage
01.gcc环境
yum install gcc-c++
02.下载Tracker、Storage依赖库 -> libevent库
yum -y install libevent
03.下载Tracker、Storage依赖库 -> libfastcommon库
a.下载
cd /usr/local
wget https://github.com/happyfish100/libfastcommon/archive/V1.0.43.tar.gz
tar -zxvf libfastcommon-1.0.43.tar.gz
b.编译
cd /usr/local/libfastcommon-1.0.43/
./make.sh
./make.sh install
04.安装Storage
a.下载
cd /usr/local
https://github.com/happyfish100/fastdfs/archive/V6.06.tar.gz
tar -zxvf fastdfs-6.06.tar.gz
b.编译
cd /usr/local/fastdfs-6.06/
./make.sh
./make.sh install
c.将conf目录下的配置文件拷贝到/etc/fdfs目录下
cd /usr/local/fastdfs-6.06/conf/
cp ./* /etc/fdfs/
d.配置storage.conf
mkdir /home/myslayers/fastdfs --创建元数据存储目录
vi /etc/fdfs/storage.conf --打开storage.conf
base_path = /home/myslayers/fastdfs
store_path0 = /home/myslayers/fastdfs
tracker_server = 192.168.2.128.:22122 --不能是127.0.0.1
#tracker_server = 192.168.209.122:22122 --注释掉另一个不用的地址
e.启动
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf start --启动Storage
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf stop --关闭Storage
3.3 nginx_fastdfs_module
01.fastdfs-nginx-module:重定向文件连接到源服务器取文件,避免客户端由于复制延迟导致的文件无法访问错误
a.下载
cd /usr/local
https://github.com/happyfish100/fastdfs-nginx-module/archive/V1.22.tar.gz
tar -zxvf fastdfs-nginx-module-1.22.tar.gz
b.将/usr/local/fastdfs-nginx-module-1.22/src/mod_fastdfs.conf拷贝到/etc/fdfs/目录下
cp /usr/local/fastdfs-nginx-module-1.22/src/mod_fastdfs.conf /etc/fdfs/
c.配置mod_fastdfs.conf
mkdir /home/myslayers/fastdfs --创建元数据存储目录
vi /etc/fdfs/mod_fastdfs.conf --打开mod_fastdfs.conf
base_path = /home/myslayers/fastdfs
store_path0 = /home/myslayers/fastdfs
tracker_server = 192.168.2.128:22122
url_have_group_name = true
02.Nginx编译时,--add-module
a.下载
cd /usr/local
wget https://nginx.org/download/nginx-1.14.0.tar.gz
tar -zxvf nginx-1.14.0.tar.gz
b.依赖
yum install -y gcc pcre pcre-devel
yum install -y openssl openssl-devel
c.编译
cd /usr/local/nginx-1.14.0/
./configure --add-module=/usr/local/fastdfs-nginx-module-1.22/src
make
make install
d.配置,请求转发
vi /usr/local/nginx/conf/nginx.conf
user root; --解决权限
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location ~/group[0-9]/ {
ngx_fastdfs_module;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
/usr/local/nginx/sbin/nginx -s reload --重启nginx
e.启动
/usr/local/nginx/sbin/nginx --启动Nginx
/usr/local/nginx/sbin/nginx -s stop --停止Nginx
03.开机自启
vi /etc/rc.local --打开文件
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart --追加
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart --追加
/usr/local/nginx/sbin/nginx --追加
chmod 755 /etc/rc.local --设置文件权限
3.4 upload download
01.pom.xml
<dependency>
<groupId>cn.bestwu</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27</version>
</dependency>
02.fastdfs-client.properties
fastdfs.connect_timeout_in_seconds = 5
fastdfs.network_timeout_in_seconds = 30
fastdfs.charset = UTF-8
fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = 80
fastdfs.tracker_servers = 192.168.2.128:22122
fastdfs.connection_pool.enabled = true
fastdfs.connection_pool.max_count_per_entry = 500
default value is 3600
fastdfs.connection_pool.max_idle_time = 3600
millisecond, default value is 1000
fastdfs.connection_pool.max_wait_time_in_ms = 1000
03.文件上传
@Test
void testUpload() throws IOException, MyException {
//创建StorageClient1
ClientGlobal.initByProperties("fastdfs-client.properties");
TrackerClient trackerClient = new TrackerClient();
TrackerServer trackerServer = trackerClient.getConnection();
StorageServer storageServer = null;
StorageClient1 client1 = new StorageClient1(trackerServer, storageServer);
//NameValuePair保存的是文件的元数据信息
NameValuePair pairs[] = null;
String filePath = client1.upload_file1("D:\\document\\Background\\2.jpg", "jpg", pairs);
System.out.println(filePath);
}
04.文件下载
@Test
void testDownload() throws IOException, MyException {
ClientGlobal.initByProperties("fastdfs-client.properties");
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
StorageClient1 client = new StorageClient1(trackerServer, storageServer);
byte[] bytes = client.download_file1("group1/M00/00/00/wKgCgF-FtTuAW7D5ABOZB_BKrKk977.jpg");
FileOutputStream fos = new FileOutputStream(new File("D:\\test.png"));
fos.write(bytes);
fos.close();
}
3.5 token check
01.开启令牌校验
vi /etc/fdfs/http.conf
http.anti_steal.check_token = true --开启校验
http.anti_steal.secret_key = FastDFS1234567890 --密钥
http.anti_steal.token_check_fail = /home/yuqing/fastdfs/conf/anti-steal.jpg
02.重启服务器
/usr/local/nginx/sbin/nginx -s stop --停止Nginx
/usr/local/nginx/sbin/nginx --启动Nginx
03.获取令牌
@Test
public void getToken() throws Exception {
int ts = (int) Instant.now().getEpochSecond();
//第一个参数:访问的文件,注意不包含 group
//第二个参数:时间戳
//第三个参数:密钥
String token = ProtoCommon.getToken("M00/00/00/wKgCgF-FtTuAW7D5ABOZB_BKrKk977.jpg", ts, "FastDFS1234567890");
StringBuilder sb = new StringBuilder();
sb.append("?token=").append(token);
sb.append("&ts=").append(ts);
System.out.println(sb.toString());
}
04.携带令牌访问
http://192.168.2.128/group1/M00/00/00/wKgCgF-FtTuAW7D5ABOZB_BKrKk977.jpg?token=5f4b1976727a3ba439fc2d8874945581&ts=1602603800
4 service
4.1 aria2
01.安装(一是命令行下载模式,二是RPC模式+网页管理)
将https://github.com/aria2/aria2/releases/tag/release-1.35.0替代文件夹中的“aria2c.exe” -> 启动aria2.exe
02.配置(aria2.conf)
a.修改默认下载目录
#文件的保存路径(可使用绝对路径或相对路径),默认: 当前启动位置
dir=D:\Download
b.修改服务器默认连接数
#同一服务器连接数,添加时可指定,默认:1,默认编译windows可设置的最大连接数为16
max-connection-per-server=16
c.开启BT下列设置
enable-dht=true
bt-enable-lpd=true
enable-peer-exchange=true
d.添加trackers,逗号隔开,获取https://github.com/XIU2/TrackersListCollection/blob/master/best_aria2.txt
bt-tracker=udp://tracker.coppersurfer.tk:6969/announce,
03.实现开机无cmd窗口启动
a.方式一:编辑HideRunAria2.vbs文件(普遍写法)
CreateObject("WScript.Shell").Run "D:\software\Linux\Window\Aria2\aria2c.exe --conf-path=aria2.conf",0
b.方式二:编辑HideRunAria2.vbs文件(防止多开)
Set wmi=GetObject("winmgmts:\\.\root\cimv2")
Set list=wmi.ExecQuery("select * from win32_process where name='aria2c.exe'")
If list.count=0 Then
Set objShell = CreateObject("Wscript.Shell")
objShell.Run "D:\software\Linux\Window\Aria2\aria2c.exe --conf-path=aria2.conf",0
End If
c.开机启动
HideRunAria2.vbs.快捷方式 -> C:\Users\13514\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
d: && cd D:\software\Linux\Window\Aria2 && nssm install Aria2 && net start Aria2
04.测试
a.命令行管理
aria2c http://example.org/mylinux.iso --下载网络文件
aria2c http://a/f.iso ftp://b/f.iso --下载多个文件
aria2c -x2 http://a/f.iso --下载时每个host使用两个连接
aria2c http://example.org/mylinux.torrent --使用BitTorrent协议下载
aria2c 'magnet:?xt=urn:btih:248D0A1CD08284299DE78D5C1ED359BB46717D8C' --使用磁力链接下载
aria2c http://example.org/mylinux.metalink --Metalink
aria2c -i uris.txt --下载text文本文件中的链接
b.网页管理(Motrix WebExtension、百度网盘助手、BaiduExporter)
Aria2 for Chrome
YAAW for Chrome
http://aria2c.com/
http://localhost:6800/jsonrpc --AriaNg设置 -> RPC地址
05.Motrix
a.安装
https://motrix.app/
b.插件
集装箱 -> 右键 -> 使用Motrix下载
c.进阶设置
Tracker 服务器 -> 自动更新
RPC 授权密钥(生成密钥、2ZMAiC7r3gqr、保存)-> Motrix Chrome Extension(2ZMAiC7r3gqr、Set Key)
4.2 seafile
01.直接编译(Seafile会自动配置 MariaDB,Memcached,WebDAV,Ngnix 和开机自动启动脚本)
a.安装
yum install wget -y
wget https://raw.githubusercontent.com/haiwen/seafile-server-installer-cn/master/seafile-server-centos-7-amd64-http
bash seafile-server-centos-7-amd64-http 6.3.3
b.运行(配置SERVICE_URL、FILE_SERVER_ROOT)
Server Address: http:/127.0.0.1
Seafile Admin:[email protected]
Admin Password:oDoac0xe
02.Docker
a.镜像
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install docker-ce -y
b.配置(右边的端口号一定不要改,左边端口号的含义是Seafile占用的端口,例如修改为1234:80)
docker run -d --name seafile \
-e SEAFILE_SERVER_HOSTNAME=seafile.example.com \
-e [email protected] \
-e SEAFILE_ADMIN_PASSWORD=password \
-v /opt/seafile-data:/shared \
-p 80:80 \
seafileltd/seafile:latest
c.运行(配置SERVICE_URL、FILE_SERVER_ROOT)
systemctl enable docker
docker update --restart=always seafile
01.Telegram
a.创建机器人
@BotFather -> /start -> /newbot -> RssBot、Bilihotbot
b.创建命令
rss - 显示当前订阅的 RSS 列表,加 raw 参数显示链接
sub - 订阅一个 RSS: /sub http://example.com/feed.xml
unsub - 退订一个 RSS: /unsub http://example.com/feed.xml
unsubthis - 使用此命令回复想要退订的 RSS 消息即可退订, 不支持 Channel
export - 导出为 OPML
c.机器人对应的Token
1513156079:AAG6RWpm_YbgaW1Nxq44_ukTwTzilPUf9gc
1759838027:AAG2GdOOhDMeGsWOZbFnVMz7pycWNs2oo_Y TELEGRAMBOTTOKEN
d.Server酱·Turbo版
SCT158050TEyUSPpKA2iMlpBtQGkVWKygC SendKey
02.安装RSSBot
a.安装,DATAFILE为数据库保存路径,TELEGRAM-BOT-TOKEN对应创建的机器人对应的Token
apt install unzip
wget https://github.com/iovxw/rssbot/releases/download/v1.4.3/rssbot-v1.4.3-linux.zip
unzip rssbot-v1.4.3-linux.zip
./rssbot DATAFILE TELEGRAM-BOT-TOKEN
b.配置
vi /etc/systemd/system/rssbot.service
[Unit]
Description=A RSS Bot
After=network.target
Wants=network.target
[Service]
Type=simple
WorkingDirectory=/home/rss
ExecStart=/home/rss/rssbot DATAFILE TELEGRAM-BOT-TOKEN
Restart=on-failure
RestartSec=10
User=rss
[Install]
WantedBy=multi-user.target
c.执行
systemctl daemon-reload
systemctl enable rssbot
systemctl start rssbot
03.Bot命令示例
个人订阅:/sub
频道订阅:/sub @channelname
查看个人订阅列表:/rss
查看个人订阅列表并显示订阅链接:/rss raw
如果需要把机器人加入频道,则机器人的身份需要为管理员
4.4 coolify
01.介绍
Coolify 开源自托管的 Heroku/Netlify/Vercel 替代方案
02.特点
自主托管:Coolify 允许部署资源到几乎任何服务器上,包括个人的服务器、树莓派等。只需要 SSH 连接,就能管理自己硬件资源。
多语言多框架支持:Coolify 与各种编程语言、框架兼容,可以部署和管理各种类型的应用程序。不论静态网站、API 后端服务还是数据库,Coolify 都能提供强大的支持。
SSL 证书和安全性:Coolify 会自动为自定义域名设置和更新 Let’s Encrypt 证书,确保应用程序的安全和加密连接。用户不需要担心证书繁琐设置和更新,Coolify 会自动处理这些问题。
监控、通知:Coolify 会监控部署、服务器磁盘使用情况等,并在发生任何问题时通过电子邮件等渠道通知。
03.安装脚本
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
注意:Coolify 支持通过源码及 Docker 等方式部署,上面是来自官方的一键部署脚本,可使用与生产环境。
04.运行要求
a.支持操作系统
基于 Debian 的 Linux 发行版(Debian/Ubuntu 等)
基于 Redhat 的 Linux 发行版(CentOS/Fedora/Red Hat/AlmaLinux/Rocky 等)
基于 SUSE 的 Linux 发行版(SLES/SUSE/openSUSE 等)
b.支持系统架构
AMD64 位架构
ARM64 位架构
c.所需的最低服务器配置
2cpu
2gb内存
30+GB的存储空间
4.5 hugging
01.介绍
a.You can create a repository from the CLI (skip if you created a repo from the website)
$ pip install huggingface_hub
# You already have it if you installed transformers or datasets
$ huggingface-cli login
# Log in using a token from huggingface.co/settings/tokens
# Create a model or dataset repo from the CLI if needed
$ huggingface-cli repo create repo_name --type {model, dataset, space}
b.Clone your model, dataset or Space locally
# Make sure you have git-lfs installed
# (https://git-lfs.github.com)
$ git lfs install
$ git clone https://huggingface.co/username/repo_name
c.Then add, commit and push any file you want, including larges files
# save files via `.save_pretrained()` or move them here
$ git add .
$ git commit -m "commit from $USER"
$ git push
d.In most cases, if you're using one of the compatible libraries, your repo will then be accessible from code, through its identifier: username/repo_name
For example for a transformers model, anyone can load it with:
tokenizer = AutoTokenizer.from_pretrained("username/repo_name")
model = AutoModel.from_pretrained("username/repo_name")
4.6 oneinstack
01.安装
a.使用镜像下载oneinstack文件
yum -y install wget screen curl python #for CentOS/Redhat
# apt-get -y install wget screen curl python #for Debian/Ubuntu
wget http://aliyun-oss.linuxeye.com/oneinstack-full.tar.gz #阿里云经典网络下载
wget http://mirrors.linuxeye.com/oneinstack-full.tar.gz #包含源码,国内外均可下载
wget http://mirrors.linuxeye.com/oneinstack.tar.gz #不包含源码,建议仅国外主机下载
b.解压并安装
tar xzf oneinstack-full.tar.gz
cd oneinstack #如果需要修改目录(安装、数据存储、Nginx日志),请修改options.conf文件
screen -S oneinstack #如果网路出现中断,可以执行命令`screen -R oneinstack`重新连接安装窗口
./install.sh #注:请勿sh install.sh或者bash install.sh这样执行
c.一键配置
a.更改ssh端口号,建议默认22,过程出现Default可直接回车
22
b.是否开启iptables,如果安全组开启,可关闭
N
c.是否安装Nginx、Apache、Tomcat(推荐:PHP使用LNMP模式,JAVA使用LNMT模式)
LNMP:安装Nginx、不安装Apache、Tomcat
(系统运行php-fpm进程)
LAMP:安装Apache、不安装Nginx、Tomcat
(无php-fpm进程,php以模块形式加载在Apache中)
LNMPA:安装Nginx、Apache,不安装Tomcat
(静态资源由Nginx处理,PHP由Apache处理,无php-fpm进程,php以模块形式加载在Apache中)
LNMT:安装Nginx、Tomcat,不安装Apache
(静态资源由Nginx处理,JAVA由Tomcat处理,可安装PHP,支持多语言环境,同时可运行PHP、JAVA)
d.是否安装数据库
Y
02.命令
./addons.sh --添加附加组件
./vhost.sh --添加虚拟主机
./vhost.sh del --删除虚拟主机
./pureftpd_vhost.sh --管理FTP账号
./backup_setup.sh --备份
./upgrade.sh --更新
./uninstall.sh --卸载
03.管理服务
a.Nginx/Tengine/OpenResty
service nginx {start|stop|status|restart|reload|configtest}
b.MySQL/MariaDB/Percona
service mysqld {start|stop|restart|reload|status}
c.PostgreSQL
service postgresql {start|stop|restart|status}
d.MongoDB
service mongod {start|stop|status|restart|reload}
e.PHP
service php-fpm {start|stop|restart|reload|status}
f.HHVM
service supervisord {start|stop|status|restart|reload}
g.Apache
service httpd {start|restart|stop}
h.Tomcat
service tomcat {start|stop|status|restart}
i.Pure-Ftpd:
service pureftpd {start|stop|restart|status}
j.Redis
service redis-server {start|stop|status|restart|reload}
k.Memcached
service memcached {start|stop|status|restart|reload}
04.ftp权限问题
a.报错
创建ftp账户后,远程连接出现550错误,提示没有权限。
b.解决:网站根目录权限遵循:文件644、文件夹755、权限用户和用户组www
chown -R www.www /data/wwwroot/
find /data/wwwroot/ -type d -exec chmod 755 {} \;
find /data/wwwroot/ -type f -exec chmod 644 {} \;
05.LNMT模式部署JAVA应用
a.采用lnmt模式,即安装nginx、mysql、tomcat
默认Nginx处理静态资源,Tomcat处理动态资源
b.域名
默认(未绑定域名)对应网站根目录/data/wwwroot/default(不是webapps),
部署代码时建议将war包解压(比如example.war,解压命令:jar xf example.war ,注意权限必须为www),将其中代码放到对应网站根目录:
如果上传代码之后目录结构为:/data/wwwroot/default/WEB-INF,访问地址为:http://IP
如果上传代码之后目录结构为:/data/wwwroot/default/example/WEB-INF,访问网站地址为:http://IP/example
c.war包
war包也可以不解压即上传到对应网站根目录,但必须注意访问路径和静态资源目录问题。
如果访问网站时,静态资源加载不了,可能是原因是做了动静分离静态资源直接有nginx处理,
请确认nginx是否能找到相关静态资源(nginx网站根目录:/data/wwwroot/default)
d.虚拟主机
如果vhost.sh绑定了域名,如www.example.com,工具会自动生成对应根目录:/data/wwwroot/www.example.com ,请将代码放入此目录
06.切换php版本
./uninstall.sh php #卸载
./install.sh #php选择y,其余选择n,即可
07.配置MySQL远程连接
a.开启iptables中3306端口
a.Centos7
iptables -I INPUT 4 -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT
service iptables save #保存iptables规则
b.Ubuntu/Debian
iptables -I INPUT 4 -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT
iptables-save > /etc/iptables.up.rules #保存iptables规则
b.授权数据库
远程连接新建一个帐号(帐号名不能为root)
如:添加一个用户名为db_user,密码为db_pass,授权为%,对db_name数据库所有权限,命令如下:
# mysql -uroot -p
MySQL [(none)]> grant all privileges on db_name.* to db_user@’%’ identified by ‘db_pass’;
MySQL [(none)]> flush privileges;
MySQL [(none)]> exit;
4.7 vaultwarden
01.VaultWarden
a.安装docker
yum update -y && yum install docker -y && systemctl start docker && systemctl enable docker && service docker status
b.安装docker-compose
curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose
c.配置docker-compose.yml
cd / && mkdir www && cd www && mkdir vaultwarden && cd /www/vaultwarden && vi docker-compose.yml
version: "3"
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: always
ports:
- "127.0.0.1:6666:80" #将宿主机6666端口映射到docker的80端口
- "127.0.0.1:3012:3012"
volumes:
- ./vw-data:/data
environment:
DOMAIN: 'https://myslayers.cn/'
WEBSOCKET_ENABLED: "true" #是否开启WebSocket
SIGNUPS_ALLOWED: "true" #是否开启注册,自用的话自己搭建好注册后改成false
WEB_VAULT_ENABLED: "true" #是否开启Web客户端
#ADMIN_TOKEN: "xxxxxx" #后台登陆密码,建议openssl rand -base64 48 生成ADMIN_TOKEN确保安全
d.启动docker-compose
cd /www/vaultwarden
docker-compose up -d --启动服务
docker-compose down --关闭服务
docker-compose restart --重启服务
docker-compose down && docker pull vaultwarden/server:latest --更新镜像,需要先停止服务
docker ps -a --查看运行
docker rm -f 80576e5ea74a --移除容器
docker images --查看镜像
docker rmi -f d55229deb03e --移除镜像
docker start 80576e5ea74a --启动容器
docker stop 80576e5ea74a --停止容器
docker restart 80576e5ea74a --重启容器
docker rm 80576e5ea74a --移除容器
docker logs 80576e5ea74a --查看日志
docker exec -it vaultwarden /bin/bash --内部环境
e.数据备份
yum install sqlite-devel -y && sqlite3 -version && sqlite3 /www/vaultwarden/vm-data/d.sqlite3 ".backup '/root/db-$(date '+%Y%m%d-%H%M').sqlite3'"
02.Let’s Encrypt
a.安装
curl https://get.acme.sh | sh && chmod -R 777 /root/.acme.sh/
b.自动续签,开启自动同步更新
cd /root/.acme.sh && alias acme.sh=~/.acme.sh/acme.sh && echo 'alias acme.sh=~/.acme.sh/acme.sh' >>/etc/profile
00 00 * * * root /root/.acme.sh/acme.sh --cron --home /root/.acme.sh &>/var/log/acme.sh.logs
/root/.acme.sh/acme.sh --upgrade --auto-upgrade
c.申请证书
export xxxxx="xxxxxxxxxxxxxxxxxxxxxxxxxx"
export xxxxx="xxxxxxxxxxxxxxxxxxxxxxxxxxx"
acme.sh --issue --dns dns_ali -d myslayers.cn -d www.myslayers.cn
d.申请证书(Nginx创建ssl文件夹,生成dhparam.pem文件,acme将证书克隆到ssl文件夹)
yum update -y && yum install -y epel-release && yum install -y nginx && cat /etc/nginx/nginx.conf && mkdir /etc/nginx/ssl && openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 && acme.sh --installcert -d myslayers.cn --key-file /etc/nginx/ssl/myslayers.cn.key --fullchain-file /etc/nginx/ssl/fullchain.cer --reloadcmd "service nginx force-reload"
03.Nginx
a.配置(cat /etc/nginx/nginx.conf)
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name myslayers.cn www.myslayers.cn;
root /usr/share/nginx/html;
ssl_certificate "/etc/nginx/ssl/fullchain.cer";
ssl_certificate_key "/etc/nginx/ssl/myslayers.cn.key";
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://127.0.0.1:6666;
proxy_http_version 1.1;
proxy_cache_bypass $http_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $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_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
}
location /notifications/hub {
proxy_pass http://127.0.0.1:3012;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /notifications/hub/negotiate {
proxy_pass http://127.0.0.1:6666;
}
location /admin {
proxy_set_header Host $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_pass http://127.0.0.1:6666;
}
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
b.启动
nginx --打开服务
nginx -v --查看版本
nginx -t --检查配置
nginx -p prefix --默认前缀(/usr/share/nginx/)
nginx -c filename --默认配置(/etc/nginx/nginx.conf)
nginx -s reopen --主进程发送信号(重启服务)
nginx -s reload --主进程发送信号(重载配置)
nginx -s stop --主进程发送信号(强制停止)
nginx -s quit --主进程发送信号(优雅退出)
ss -ntlp| grep -i nginx --查看软件是否正常运行
systemctl enable | start | stop | restart nginx --systemctl命令
04.启动
a.访问
https://myslayers.cn/
b.二次验证
https://myslayers.cn/admin -> SMTP Email Settings、Email 2FA Settings
Enabled Default: true(勾选)
Host smtp.163.com(填写)
Enable Secure SMTP Default: true(勾选)
Force TLS Default: false(勾选)
Port 465(填写)
From Address [email protected] (填写)
From Name Vaultwarden(填写)
Username [email protected] (填写)
Password RBMWIHQZJTMYOLNG
SMTP Auth mechanism 无
SMTP connection timeout 15
Server name sent during HELO 无
Enable SMTP debugging (Know the risks!) 无
Accept Invalid Certs (Know the risks!) 无
Accept Invalid Hostnames (Know the risks!) 无
Test SMTP [email protected] -> Send test mail
4.8 lookingglass
01.利用Oneinstack安装nginx、php7.2
wget -c http://mirrors.linuxeye.com/oneinstack-full.tar.gz && tar xzf oneinstack-full.tar.gz && ./oneinstack/install.sh --nginx_option 1 --php_option 7
02.由于LookingGlass需要PHP中某些禁用的函数,因此需要配置PHP
vi /usr/local/php/etc/php.ini
:set nu -> 311行 -> disable_functions代表禁用函数 -> 删除proc开头的函数,以及函数后面的逗号
service php-fpm restart
03.安装LookingGlass
a.下载
wget https://github.com/ILLKX/LookingGlass/archive/master.zip && unzip master.zip
b.运行脚本
rm -f /data/wwwroot/default/index.html
mv LookingGlass-master/* /data/wwwroot/default/
bash /data/wwwroot/default/LookingGlass/configure.sh
c.填写规范
如果项目放于Nginx目录下时,http://xxx.com(最后不要加"/")
如果项目放于Nginx目录下的某个文件夹时,http://xxx.com/xxx(最后不要加"/")
Enter your website name (Header/Logo) []: SpeedTest
Enter the public URL to this LG (including http://) []: http://halavah.buzz
Enter the servers location []: Tokyo, Japan
Enter the test IPv4 address []: 202.182.112.34
Enter the test IPv6 address (Re-enter everytime this script is run) []:
Enter the size of test files in MB (Example: 25 50MB 100) []: 100MB
Do you wish to enable rate limiting of network commands? (y/n): n
Enter the username of your webserver (E.g. www-data): root
Enter the user group of your webserver (E.g. www-data): root
04.测试
http://halavah.buzz
5 blogger
5.1 hexo
00.汇总
a.Gitee Pages
仅支持 Jekyll、Hugo、Hexo编译静态资源
-----------------------------------------------------------------------------------------------------
如何创建一个首页访问地址不带二级目录的 pages,如ipvb.gitee.io?
答:如果你想你的 pages 首页访问地址不带二级目录,如ipvb.gitee.io,你需要建立一个与自己个性地址同名的仓库,
如 https://gitee.com/ipvb 这个用户,想要创建一个自己的站点,但不想以子目录的方式访问,
想以ipvb.gitee.io直接访问,那么他就可以创建一个名字为ipvb的仓库 https://gitee.com/ipvb/ipvb 部署完成后,
就可以以 https://ipvb.gitee.io 进行访问了。
b.私有仓库支持性
Vercel Pages支持连接私有仓库
Netlify Pages支持连接私有仓库
Cloudflare Pages不能连接私有仓库
GitHub的私有仓库开启GitHub Pages需要升级为Pro用户($4/mon)
c.gihtub page
a.前提
必须仓库为公有public
b.不使用Action
settings -> pages -> Build and deployment -> Deploy from a branch -> master、/docs
c.使用Action
.github/workflows/deploy.yml,该文件指定构建目录,如public;指定构建分支,如master
settings -> pages -> Build and deployment -> GitHub Actions
GitHub Actions -> 查看构建情况
01.Hexo托管
a.托管方式(Gitee)-> 手动更新
名称:myslayers
描述:勿因喜而轻诺!
插件:d: && cd D:\software_ware\workspace_blog && cnpm install hexo-deployer-git --save
邮箱:git config --global user.email "[email protected] " && git config --global user.name "myslayers"
开启Gitee Pages服务:Branch(master)、整个目录
站点_config.yml文件:
title: 个人博客
subtitle: ''
description: '勿因喜而轻诺'
keywords:
author: myslayers
language: zh-CN
timezone: 'Asia/Shanghai'
----------------------------------------------------------------------
url: https://myslayers.gitee.io/
root: /
permalink: :title.html
----------------------------------------------------------------------
public_dir: public
----------------------------------------------------------------------
theme: keep
----------------------------------------------------------------------
deploy:
type: 'git'
repo: 'https://gitee.com/myslayers/myslayers.git'
branch: master
message:
b.托管方式(Github)-> 自动更新
名称:myslayers.github.io
描述:勿因喜而轻诺!
插件:d: && cd D:\software_ware\workspace_blog && cnpm install hexo-deployer-git --save
邮箱:git config --global user.email "[email protected] " && git config --global user.name "myslayers"
开启Github Pages服务:Branch(master)、docs目录
站点_config.yml文件:
title: Halavah's Blog
subtitle: ''
description: '勿因喜而轻诺!'
keywords:
author: Halavah
language: zh-CN
timezone: 'Asia/Shanghai'
----------------------------------------------------------------------
url: https://halavah.github.io/halavah
root: /halavah/
permalink: :title.html
----------------------------------------------------------------------
public_dir: docs
----------------------------------------------------------------------
theme: Chic
----------------------------------------------------------------------
deploy:
type: 'git'
repo: 'https://github.com/halavah/halavah.git'
branch: master
message:
c.自定义域名(Github)
a.Cloudflare
类型 名称 内容 TTL 代理状态
A @ 185.199.108.153 自动 仅限 DNS
A @ 185.199.109.153 自动 仅限 DNS
A @ 185.199.110.153 自动 仅限 DNS
A @ 185.199.111.153 自动 仅限 DNS
CNAME www halavah.github.io 自动 仅限 DNS
b.Settings
master /docs
halavah.tk
Enforce HTTPS Please allow 24 hours for this process to complete
c._config.yml
url: https://halavah.tk
root: /
d.防止删除CNAME文件
将CNAME文件放到source文件夹下,那么在hexo generate在编译时,也会将CNAME编译进docs文件夹中
e.docs放CNAME
https://halavah.github.io/halavah
02.Hexo部署
a.部署方式(git push)(每次提交需要add、commit、ppush,同时需要手动输入邮箱、密码)
a.创建本地仓库、远程仓库
git init --创建本地仓库
[email protected] :myslayers/myslayers.github.io.git--创建远程仓库
b.关联本地仓库与远程仓库地址
git remote add origin https://github.com/myslayers/myslayers.github.io.git
c.保留线上的readme文件(如果本地分支版本大于远程版本,则强制提交)
git pull origin master
d.关联本地分支与远程分支地址
git add .
git commit -m "my first commit"
git push origin master -f --强制提交:舍弃线上文件进行强制推送(不推荐)
git push origin master --正常提交:保留线上的readme文件
b.部署方式(hexo deploy)
hexo clean && hexo generate && hexo deploy
hexo clean && hexo generate && hexo s -p 9999
03.Hexo使用(NexT、Keep、目前Chic、yilia、Concise、Fluid、Flui、Inside)(Typecho-handsome)(Typecho)
a.环境(Nodejs、Git、hexo-cli)(在Disk中默认Nodejs编译cnpm、hexo-cli,默认Git,因此可以忽略此步骤)
D:\software\Linux\Window\Git
D:\software\JavaScript\Nodejs
npm install -g cnpm --registry=https://registry.npm.taobao.org && cnpm install -g hexo-cli
b.安装
d: && mkdir D:\software_ware\workspace_hexo --创建blog文件夹
d: && cd D:\software_ware\workspace_hexo && hexo init --初始化hexo框架
c.命令
hexo init [folder] --初始化命令,[folder]表示初始化的文件夹
hexo new [layout] <title> --新建文章或页面,[layout]表示页面, <title>表示标题
hexo s -p 9999 --本地查看网站
hexo generate --生成网站静态文件,网页默认保存在“public文件夹”
hexo clean --清空“public文件夹的内容”
hexo deploy --部署网站,将“public文件夹的内容”进行部署
hexo version --当前hexo版本号
d.启动
git clone [email protected] :halavah/PicGo.git workspace_hexo --第1步:克隆仓库
git pull --rebase --第2步:更新仓库
hexo clean && hexo generate && hexo s -p 9999 --第3步:查看本地(check.bat)(重新生成docs)
hexo clean && hexo generate && hexo deploy --第4步_无:远程部署(deploy.bat)(删除配置)
git add . && git commit -m 'v1.0' && git push --第5步:手动提交
git tag v1.0 && git push origin v1.0 --第6步:手动提交
e.Keep主题
a.功能
Post_top(文章顶置)
base_info(网站名称、作者昵称、网站域名)
style(网站主题色、文章内容页的图片排列位置、左侧TOC目录结构模块的宽度、设置鼠标悬浮时的样式、首屏模块)
social_contact(社交网络链接,仅在首屏下生效)
menu(导航菜单)
rss(订阅)
comment(Gitalk评论)
website_count(计数项)
local_search(本地搜索)
post_wordcount(文章字数统计和阅读时长统计功能)
home_article(首页文章块底部的显示设置)
code_copy(代码复制)
side_tools(右下角工具)
back2top(一键快速 回到顶部和到达底部)
toc(查看文章结构和跳转)
copyright_info(文章内容页的版权信息模块)
cdn(开启资源CDN加速)
footer(网站最底部的信息展示设置)
MathJax(数学公式)
lazyload(懒加载)
pjax(Ajax部分更新)
b.写作
---
title: 第一篇文章
date: 2020-04-07 21:55:14
tags: 标签一
categories: 分类一
comment: true --评论
mathjax: true --MathJax数学公式
sticky: 9999 --sticky值越大,顶置的文章越靠前
---
f.Chic主题
a.安装
cd your-blog/themes
git clone https://github.com/Siricee/hexo-theme-Chic.git Chic
hexo new page tag
hexo new page category
hexo new page about
b.写作
---
title: 第一篇文章
date: 2020-04-07 21:55:14
tags: 标签一
categories: 分类一
mathjax: true --MathJax数学公式
---
5.2 hugo
01.命令(PaperMod、Even、MemE、LoveIt)
hugo new site myslayers -f yml --初始化,文件夹myslayers,站点http://myslayers.com
hugo new --kind post archetypes/post.md --归档
hugo new --kind post tags/post.md --标签
hugo server -D --本地查看网站(http://localhost:1313/)
02.主题
https://themes.gohugo.io/hugo-papermod/
https://github.com/adityatelange/hugo-PaperMod
03.发布
a.第一次发布
cd public
git init
git remote add origin https://github.com/Showfom/showfom.github.io.git
git add .
git commit -m "first commit"
git push -u origin master
b.后续发布
cd public
git add .
git status
git commit -m "add blog post"
git push
5.3 picgo
01.GitHub
仓库名 halavah/PicGo
分支名 master
Token 5ef48dd7ead044453f7606442ce8d04ccc365c23
存储路径 avatar/ background/
自定义域名 https://halavah.buzz
02.默认路径
https://raw.githubusercontent.com/[username]/[仓库名]/[分支名]/[文件路径]
https://raw.githubusercontent.com/halavah/PinGo/master/background/22.jpg
03.加速路径
https://cdn.jsdelivr.net/gh/[username]/[仓库名]@[分支名]/[文件路径]
https://cdn.jsdelivr.net/gh/halavah/PinGo@master/background/22.jpg
04.域名路径
https://halavah.buzz/[文件路径]
https://halavah.buzz/background/22.jpg
5.4 quartz1
00.起源
a.分类1
TroyeKK小站
TroyeKK World
b.分类2
TroyeHub、TroyeVibe、KKZone、TroyeNest、KKSpot、TroyeWorld、TroyeBox、KKLink、TroyeX、TroyeHQ
c.World换个词
Realm、Horizon、Sphere、Domain、Territory、Kingdom、Vista、Universe、Oasis、Empire
d.版本说明
quartz-v0_没有防护码
quartz-v1_仅适配域名_如vercel_session:采用sessionStorage来实现,可以通过绕开验证,通过【会话存储】使用【verified】设置为【true】
quartz-v1_仅适配域名+仓库_如github_session:采用sessionStorage来实现,可以通过绕开验证,通过【会话存储】使用【verified】设置为【true】
quartz-v2_仅适配域名_如vercel_token:采用sessionStorage来实现,但是token分为3个部分,localStorage存储一部分、sessionStorage 存储另一部分、cookie存储第三部分,但是【ChatGPT】可推测出密码
quartz-v3_仅适配域名_如vercel_不可逆加密:采用sessionStorage来实现,但是token分为3个部分,localStorage存储一部分、sessionStorage 存储另一部分、cookie存储第三部分,但是【不可逆加密】,【ChatGPT】不能推测出密码
e.启动
$ npx quartz build --verbose ,构建到public,但不运行
$ npx quartz build --serve,默认监听在 8080 端口,支持热重载,但是不支持网络文件系统的热重载。
f.硬链接
mklink /d "D:\software_xare\workspace_open\quartz-pro_screen\content" "D:\software_ware\04.Directory04"
mklink /d "D:\software_ware\99.Directory01\content" "D:\software_ware\01.Directory01"
mklink /d "D:\software_ware\99.Directory02\content" "D:\software_ware\02.Directory02"
mklink /d "D:\software_ware\99.Directory03\content" "D:\software_ware\03.Directory03"
mklink /d "D:\software_ware\99.Directory04\content" "D:\software_ware\04.Directory04"
mklink /d "D:\software_ware\99.Directory05\content" "D:\software_ware\05.Directory05"
g.git检查Aliyun Key
搜索accessKey、secretKey、accessKeyId、accessKeySecret
00.project1
02.backend2
06.cangqiong
07.jiankang
01.使用
a.下载
https://github.com/jackyzha0/quartz
b.安装和初始化
[[quartz]] 支持利用 nodejs 直接部署,以及利用 docker 部署。
# nodejs 部署和初始化
$ git clone https://github.com/jackyzha0/quartz.git
$ cd quartz
$ npm i
$ npx quartz create
$ npx quartz build --serve
---------------------------------------------------------------------------------------------------------
# docker部署
$ git clone https://github.com/jackyzha0/quartz.git
$ docker run --rm -itp 8080:8080 $(docker build -q .)
c.配置quartz.config.ts 和quartz.layout.ts文件
quartz.config.ts 文件主要是配置网站信息,主题自定义以及插件系统,默认基本不用动,只需要更改一下网站信息即可,具体参考Configuration (jzhao.xyz)。
quartz.layout.ts 文件是配置布局,默认有 3 个布局样式可以自定义:
sharedPageComponents :这个是配置分享页面内容的,主要是配置页脚信息。
defaultContentPageLayout:这个是配置文档页面布局的,注意主页也属于文档。
defaultListPageLayout :这个是配置标签页和文件夹页面布局的。
布局参考:Layout (jzhao.xyz)
组件参考:Components (jzhao.xyz)
d.生成和预览
$ npx quartz build --verbose ,构建到public,但不运行
$ npx quartz build --serve,默认监听在 8080 端口,支持热重载,但是不支持网络文件系统的热重载。
e.同步内容
文档内容全部在content目录,该文件夹下应该有index.md 作为主页,content 中的文档结构会默认的渲染成路径。
f.启动脚本:start.bat
@echo off
:: Navigate to the directory where the script is located
cd /d "%~dp0"
:: Delete all contents in the "public" folder but keep the folder itself
if exist "public" (
echo Deleting all contents in the "public" folder...
del /q /f "public\*.*"
for /d i"
echo Deletion completed.
) else (
echo "The public folder does not exist."
)
npx quartz build --serve
g.命令说明
npx quartz build --serve
其中大多数都有合理的默认值,但如果您有自定义设置,则可以覆盖它们:
-d或--directory:内容文件夹。这通常只是content
-v或者--verbose:打印额外的日志信息
-o或--output:输出文件夹。这通常只是public
--serve:运行本地热重载服务器来预览你的 Quartz
--port:在哪个端口上运行本地预览服务器
--concurrency:解析笔记需要使用多少个线程
02.配置样式
a.根目录
a.网址:quartz.config.ts
a.11行
pageTitle: "TroyeKK小站",
pageTitle: "TroyeKK World",
pageTitle: "Halavah's Blog",
b.19行
baseUrl: "halavah.github.io",
ignorePatterns: ["private", "templates", ".obsidian", ".obsidian_android", ".trash", "_assets"],
c.20241220
import { QuartzConfig } from "./quartz/cfg"
import * as Plugin from "./quartz/plugins"
/**
* Quartz 4.0 Configuration
*
* See https://quartz.jzhao.xyz/configuration for more information.
*/
const config: QuartzConfig = {
configuration: {
pageTitle: "TroyeKK World",
pageTitleSuffix: "",
enableSPA: true,
enablePopovers: true,
analytics: {
provider: "plausible",
},
locale: "en-US",
baseUrl: "halavah.github.io",
ignorePatterns: ["private", "templates", ".obsidian", ".obsidian_android", ".trash", "_assets"],
defaultDateType: "created",
generateSocialImages: false,
theme: {
fontOrigin: "googleFonts",
cdnCaching: true,
typography: {
header: "Schibsted Grotesk",
body: "Source Sans Pro",
code: "IBM Plex Mono",
},
colors: {
lightMode: {
light: "#faf8f8",
lightgray: "#e5e5e5",
gray: "#b8b8b8",
darkgray: "#4e4e4e",
dark: "#2b2b2b",
secondary: "#284b63",
tertiary: "#84a59d",
highlight: "rgba(143, 159, 169, 0.15)",
textHighlight: "#fff23688",
},
darkMode: {
light: "#161618",
lightgray: "#393639",
gray: "#646464",
darkgray: "#d4d4d4",
dark: "#ebebec",
secondary: "#7b97aa",
tertiary: "#84a59d",
highlight: "rgba(143, 159, 169, 0.15)",
textHighlight: "#b3aa0288",
},
},
},
},
plugins: {
transformers: [
Plugin.FrontMatter(),
Plugin.CreatedModifiedDate({
priority: ["frontmatter", "filesystem"],
}),
Plugin.SyntaxHighlighting({
theme: {
light: "github-light",
dark: "github-dark",
},
keepBackground: false,
}),
Plugin.ObsidianFlavoredMarkdown({ enableInHtmlEmbed: false }),
Plugin.GitHubFlavoredMarkdown(),
Plugin.TableOfContents(),
Plugin.CrawlLinks({ markdownLinkResolution: "shortest" }),
Plugin.Description(),
Plugin.Latex({ renderEngine: "katex" }),
],
filters: [Plugin.RemoveDrafts()],
emitters: [
Plugin.AliasRedirects(),
Plugin.ComponentResources(),
Plugin.ContentPage(),
Plugin.FolderPage(),
Plugin.TagPage(),
Plugin.ContentIndex({
enableSiteMap: true,
enableRSS: true,
}),
Plugin.Assets(),
Plugin.Static(),
Plugin.NotFoundPage(),
],
},
}
export default confige
b.友链:quartz.layout.ts
a.11行
// GitHub: "https://github.com/halavah",
// BiliBili: "https://space.bilibili.com/71393128/",
b.32行
right: [
// Component.Graph(),
Component.DesktopOnly(Component.TableOfContents()),
// Component.Backlinks(),
],
c.20241220
import { PageLayout, SharedLayout } from "./quartz/cfg"
import * as Component from "./quartz/components"
// components shared across all pages
export const sharedPageComponents: SharedLayout = {
head: Component.Head(),
header: [],
afterBody: [],
footer: Component.Footer({
links: {
// GitHub: "https://github.com/halavah",
// BiliBili: "https://space.bilibili.com/71393128/",
},
}),
}
// components for pages that display a single page (e.g. a single note)
export const defaultContentPageLayout: PageLayout = {
beforeBody: [
Component.Breadcrumbs(),
Component.ArticleTitle(),
Component.ContentMeta(),
Component.TagList(),
Component.MobileOnly(Component.TableOfContents()),
],
left: [
Component.PageTitle(),
Component.MobileOnly(Component.Spacer()),
Component.Search(),
Component.DesktopOnly(Component.Explorer()),
Component.DesktopOnly(Component.About()),
Component.MobileOnly(Component.Darkmode()),
],
right: [
Component.Graph(),
Component.DesktopOnly(Component.TableOfContents()),
// Component.Backlinks(),
],
}
// components for pages that display lists of pages (e.g. tags or folders)
export const defaultListPageLayout: PageLayout = {
beforeBody: [
Component.Breadcrumbs(),
Component.ArticleTitle(),
Component.ContentMeta(),
],
left: [
Component.PageTitle(),
Component.MobileOnly(Component.Spacer()),
Component.Search(),
Component.DesktopOnly(Component.Explorer()),
Component.DesktopOnly(Component.About()),
Component.MobileOnly(Component.Darkmode()),
],
right: [
],
}
b.css
a.基础CSS:quartz/styles/base.scss
a.181行
& .sidebar {
gap: 2rem;
top: 0;
box-sizing: border-box;
padding: $topSpacing 2rem 2rem 2rem;
display: flex;
height: 100vh;
position: sticky;
}
b.546行
ul.overflow,
ol.overflow {
max-height: 100%;
//overflow-y: auto;
// clearfix
content: "";
clear: both;
& > li:last-of-type {
margin-bottom: 30px;
}
/*&:after {
pointer-events: none;
content: "";
width: 100%;
height: 50px;
position: absolute;
left: 0;
bottom: 0;
opacity: 1;
transition: opacity 0.3s ease;
background: linear-gradient(transparent 0px, var(--light));
}*/
}
c.229行
& .page-header,
& .page-footer {
margin-top: 1rem;
}
b.变量CSS:quartz/styles/variables.scss
a.18行
$sidePanelWidth: 280px; //380px;
b.19行
$topSpacing: 1rem;
c.21行
$semiBoldWeight: 470;
c.TroyeKK小站
a.quartz/components/PageTitle.tsx,16行
PageTitle.css = `
.page-title {
font-size: 1.75rem;
margin: 0;
}
`
d.搜索
a.quartz/components/Search.tsx,23行
前
<p>{i18n(cfg.locale).components.search.title}</p>
-------------------------------------------------------------------------------------------------
后
<p>搜索</p>
e.大纲
a.quartz/components/TableOfContents.tsx,36行
前
<h3>{i18n(cfg.locale).components.tableOfContents.title}</h3>
-------------------------------------------------------------------------------------------------
后
<h3>大纲</h3>
b.quartz/components/styles/toc.scss,3行
前
.toc {
display: flex;
flex-direction: column;
&.desktop-only {
max-height: 40%;
}
}
-------------------------------------------------------------------------------------------------
后
.toc {
display: flex;
flex-direction: column;
&.desktop-only {
max-height: 50%;
}
}
c.quartz/components/styles/toc.scss,45行
前:大纲滚动条
//#toc-content {
// list-style: none;
// overflow: hidden;
// overflow-y: auto;
// max-height: 100%;
// transition:
// max-height 0.35s ease,
// visibility 0s linear 0s;
// position: relative;
// visibility: visible;
//
// &.collapsed {
// max-height: 0;
// transition:
// max-height 0.35s ease,
// visibility 0s linear 0.35s;
// visibility: hidden;
// }
//
// &.collapsed > .overflow::after {
// opacity: 0;
// }
//
// & ul {
// list-style: none;
// margin: 0.5rem 0;
// padding: 0;
// & > li > a {
// color: var(--dark);
// opacity: 0.35;
// transition:
// 0.5s ease opacity,
// 0.3s ease color;
// &.in-view {
// opacity: 0.75;
// }
// }
// }
// > ul.overflow {
// max-height: none;
// width: 100%;
// }
//
// @for $i from 0 through 6 {
// & .depth-#{$i} {
// padding-left: calc(1rem * #{$i});
// }
// }
//}
-------------------------------------------------------------------------------------------------
后:大纲滚动条
#toc-content {
list-style: none;
overflow: hidden;
overflow-y: auto;
max-height: 100%;
transition:
max-height 0.35s ease,
visibility 0s linear 0s;
position: relative;
visibility: visible;
// 自定义滚动条样式
&::-webkit-scrollbar {
width: 6px; // 滚动条宽度
height: 6px; // 滚动条高度(对于横向滚动条)
}
&::-webkit-scrollbar-thumb {
background: var(--secondary); // 滚动条滑块颜色
border-radius: 3px; // 圆角滑块
}
&::-webkit-scrollbar-thumb:hover {
background: var(--tertiary); // 滑块悬停时颜色
}
&::-webkit-scrollbar-track {
background: var(--light); // 滚动条轨道颜色
border-radius: 3px; // 圆角轨道
}
&.collapsed {
max-height: 0;
transition:
max-height 0.35s ease,
visibility 0s linear 0.35s;
visibility: hidden;
}
&.collapsed > .overflow::after {
opacity: 0;
}
& ul {
list-style: none;
margin: 0.5rem 0;
padding: 0;
& > li > a {
color: var(--dark);
//opacity: 0.35;
transition:
0.5s ease opacity,
0.3s ease color;
&.in-view {
opacity: 0.75;
}
}
}
> ul.overflow {
max-height: none;
width: 100%;
}
@for $i from 0 through 6 {
& .depth-#{$i} {
padding-left: calc(1rem * #{$i});
}
}
}
f.目录
a.quartz/components/Explorer.tsx,99行
前
<h2>{opts.title ?? i18n(cfg.locale).components.explorer.title}</h2>
-------------------------------------------------------------------------------------------------
后
<h2>目录</h2>
b.quartz/components/styles/explorer.scss,67行
前
//#explorer-content {
// list-style: none;
// overflow: hidden;
// overflow-y: auto;
// max-height: 100%;
// transition:
// max-height 0.35s ease,
// visibility 0s linear 0s;
// margin-top: 0.5rem;
// visibility: visible;
//
// &.collapsed {
// max-height: 0;
// transition:
// max-height 0.35s ease,
// visibility 0s linear 0.35s;
// visibility: hidden;
// }
//
// & ul {
// list-style: none;
// margin: 0.08rem 0;
// padding: 0;
// transition:
// max-height 0.35s ease,
// transform 0.35s ease,
// opacity 0.2s ease;
// & li > a {
// color: var(--dark);
// opacity: 0.75;
// pointer-events: all;
// }
// }
// > #explorer-ul {
// max-height: none;
// }
//}
---------------------------------------------------------------------------------------------
后
#explorer-content {
list-style: none;
overflow: hidden;
overflow-y: auto;
max-height: 100%;
transition:
max-height 0.35s ease,
visibility 0s linear 0s;
margin-top: 0.5rem;
visibility: visible;
/* 自定义滚动条样式 */
&::-webkit-scrollbar {
width: 6px; /* 滚动条宽度 */
height: 6px; /* 滚动条高度(对于横向滚动条) */
}
&::-webkit-scrollbar-thumb {
background: var(--secondary); /* 滚动条滑块颜色 */
border-radius: 3px; /* 圆角滑块 */
}
&::-webkit-scrollbar-thumb:hover {
background: var(--tertiary); /* 滑块悬停时颜色 */
}
&::-webkit-scrollbar-track {
background: var(--light); /* 滚动条轨道颜色 */
border-radius: 3px; /* 圆角轨道 */
}
&.collapsed {
max-height: 0;
transition:
max-height 0.35s ease,
visibility 0s linear 0.35s;
visibility: hidden;
}
& ul {
list-style: none;
margin: 0.08rem 0;
padding: 0;
transition:
max-height 0.35s ease,
transform 0.35s ease,
opacity 0.2s ease;
& li > a {
color: var(--dark);
opacity: 0.75;
pointer-events: all;
}
}
> #explorer-ul {
max-height: none;
}
/* 深度缩进 */
@for $i from 0 through 6 {
& .depth-#{$i} {
padding-left: calc(1rem * #{$i});
}
}
}
g.关于我
a.quartz/components/About.tsx
// @ts-ignore: this is safe, we don't want to actually make darkmode.inline.ts a module as
// modules are automatically deferred and we don't want that to happen for critical beforeDOMLoads
// see: https://v8.dev/features/modules#defer
import darkmodeScript from "./scripts/darkmode.inline"
import styles from "./styles/about.scss"
import {QuartzComponent, QuartzComponentConstructor, QuartzComponentProps} from "./types"
import {i18n} from "../i18n"
import {classNames} from "../util/lang"
const About: QuartzComponent = ({displayClass, cfg}: QuartzComponentProps) => {
return (
<div className={classNames(displayClass, "about")}>
<div className="link-container">
<ul>
<li>
<a href="https://github.com/halavah" target="_blank">
<svg t="1734574903988" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1446" width="25" height="25">
<path d="M498.894518 100.608396c-211.824383 0-409.482115 189.041494-409.482115 422.192601 0 186.567139 127.312594 344.783581 295.065226 400.602887 21.13025 3.916193 32.039717-9.17701 32.039717-20.307512 0-10.101055 1.176802-43.343157 1.019213-78.596056-117.448946 25.564235-141.394311-49.835012-141.394311-49.835012-19.225877-48.805566-46.503127-61.793368-46.503127-61.793368-38.293141-26.233478 3.13848-25.611308 3.13848-25.611308 42.361807 2.933819 64.779376 43.443441 64.779376 43.443441 37.669948 64.574714 98.842169 45.865607 122.912377 35.094286 3.815909-27.262924 14.764262-45.918819 26.823925-56.431244-93.796246-10.665921-192.323237-46.90017-192.323237-208.673623 0-46.071292 16.498766-83.747379 43.449581-113.332185-4.379751-10.665921-18.805298-53.544497 4.076852-111.732757 0 0 35.46063-11.336186 116.16265 43.296085 33.653471-9.330506 69.783343-14.022365 105.654318-14.174837 35.869952 0.153496 72.046896 4.844332 105.753579 14.174837 80.606853-54.631248 116.00813-43.296085 116.00813-43.296085 22.935362 58.18826 8.559956 101.120049 4.180206 111.732757 27.052123 29.584806 43.443441 67.260893 43.443441 113.332185 0 162.137751-98.798167 197.850114-192.799074 208.262254 15.151072 13.088086 28.65155 38.804794 28.65155 78.17957 0 56.484456-0.459464 101.94381-0.459464 115.854635 0 11.235902 7.573489 24.381293 29.014824 20.2543C825.753867 867.330798 933.822165 709.10924 933.822165 522.700713c0-233.155201-224.12657-422.192601-434.927647-422.192601L498.894518 100.608396z" fill="#3F3F3F" p-id="1447"></path>
</svg>
<span style="position: relative; top: -5px;">GitHub</span>
</a>
</li>
<li>
<a href="https://space.bilibili.com/71393128/" target="_blank">
<svg t="1734575058981" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2445" width="25" height="25">
<path
d="M777.514667 131.669333a53.333333 53.333333 0 0 1 0 75.434667L728.746667 255.829333h49.92A160 160 0 0 1 938.666667 415.872v320a160 160 0 0 1-160 160H245.333333A160 160 0 0 1 85.333333 735.872v-320a160 160 0 0 1 160-160h49.749334L246.4 207.146667a53.333333 53.333333 0 0 1 75.392-75.434667l113.152 113.152c3.370667 3.370667 6.186667 7.04 8.448 10.965333h137.088c2.261333-3.925333 5.12-7.68 8.490667-11.008l113.109333-113.152a53.333333 53.333333 0 0 1 75.434667 0z m1.152 231.253334H245.333333a53.333333 53.333333 0 0 0-53.205333 49.365333l-0.128 4.010667v320c0 28.117333 21.76 51.114667 49.365333 53.162666l3.968 0.170667h533.333334a53.333333 53.333333 0 0 0 53.205333-49.365333l0.128-3.968v-320c0-29.44-23.893333-53.333333-53.333333-53.333334z m-426.666667 106.666666c29.44 0 53.333333 23.893333 53.333333 53.333334v53.333333a53.333333 53.333333 0 1 1-106.666666 0v-53.333333c0-29.44 23.893333-53.333333 53.333333-53.333334z m320 0c29.44 0 53.333333 23.893333 53.333333 53.333334v53.333333a53.333333 53.333333 0 1 1-106.666666 0v-53.333333c0-29.44 23.893333-53.333333 53.333333-53.333334z"
p-id="2446"></path>
</svg>
<span style="position: relative; top: -5px;">BiliBili</span>
</a>
</li>
</ul>
</div>
<div className="home-container">
<div className="about-container">
<a href="/">
<svg t="1734575352208" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3589" width="25" height="25">
<path
d="M452.266667 119.466667a99.555556 99.555556 0 0 1 119.466666 0l284.444445 213.333333c25.031111 18.773333 39.822222 48.355556 39.822222 79.644444v426.666667A99.555556 99.555556 0 0 1 796.444444 938.666667H227.555556a99.555556 99.555556 0 0 1-99.555556-99.555556v-426.666667c0-31.288889 14.791111-60.871111 39.822222-79.644444l284.444445-213.333333z m68.266666 68.266666a14.222222 14.222222 0 0 0-17.066666 0l-284.444445 213.333334a14.222222 14.222222 0 0 0-5.688889 11.377777v426.666667c0 7.850667 6.371556 14.222222 14.222223 14.222222h568.888888a14.222222 14.222222 0 0 0 14.222223-14.222222v-426.666667a14.222222 14.222222 0 0 0-5.688889-11.377777l-284.444445-213.333334z"
p-id="3590"></path>
<path d="M455.111111 668.444444a14.222222 14.222222 0 0 0-14.222222 14.222223v227.555555h-85.333333v-227.555555c0-54.954667 44.600889-99.555556 99.555555-99.555556h113.777778c54.954667 0 99.555556 44.600889 99.555555 99.555556v227.555555h-85.333333v-227.555555a14.222222 14.222222 0 0 0-14.222222-14.222223H455.111111z" p-id="3591"></path>
</svg>
<span style="position: relative; top: -5px;">Index</span>
</a>
</div>
<button class="changemode" id="changemode">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
version="1.1"
id="dayIcon"
x="0px"
y="0px"
viewBox="0 0 35 35"
style="enable-background:new 0 0 35 35"
xmlSpace="preserve"
aria-label={i18n(cfg.locale).components.themeToggle.darkMode}
>
<title>{i18n(cfg.locale).components.themeToggle.darkMode}明/暗</title>
<path
d="M6,17.5C6,16.672,5.328,16,4.5,16h-3C0.672,16,0,16.672,0,17.5 S0.672,19,1.5,19h3C5.328,19,6,18.328,6,17.5z M7.5,26c-0.414,0-0.789,0.168-1.061,0.439l-2,2C4.168,28.711,4,29.086,4,29.5 C4,30.328,4.671,31,5.5,31c0.414,0,0.789-0.168,1.06-0.44l2-2C8.832,28.289,9,27.914,9,27.5C9,26.672,8.329,26,7.5,26z M17.5,6 C18.329,6,19,5.328,19,4.5v-3C19,0.672,18.329,0,17.5,0S16,0.672,16,1.5v3C16,5.328,16.671,6,17.5,6z M27.5,9 c0.414,0,0.789-0.168,1.06-0.439l2-2C30.832,6.289,31,5.914,31,5.5C31,4.672,30.329,4,29.5,4c-0.414,0-0.789,0.168-1.061,0.44 l-2,2C26.168,6.711,26,7.086,26,7.5C26,8.328,26.671,9,27.5,9z M6.439,8.561C6.711,8.832,7.086,9,7.5,9C8.328,9,9,8.328,9,7.5 c0-0.414-0.168-0.789-0.439-1.061l-2-2C6.289,4.168,5.914,4,5.5,4C4.672,4,4,4.672,4,5.5c0,0.414,0.168,0.789,0.439,1.06 L6.439,8.561z M33.5,16h-3c-0.828,0-1.5,0.672-1.5,1.5s0.672,1.5,1.5,1.5h3c0.828,0,1.5-0.672,1.5-1.5S34.328,16,33.5,16z M28.561,26.439C28.289,26.168,27.914,26,27.5,26c-0.828,0-1.5,0.672-1.5,1.5c0,0.414,0.168,0.789,0.439,1.06l2,2 C28.711,30.832,29.086,31,29.5,31c0.828,0,1.5-0.672,1.5-1.5c0-0.414-0.168-0.789-0.439-1.061L28.561,26.439z M17.5,29 c-0.829,0-1.5,0.672-1.5,1.5v3c0,0.828,0.671,1.5,1.5,1.5s1.5-0.672,1.5-1.5v-3C19,29.672,18.329,29,17.5,29z M17.5,7 C11.71,7,7,11.71,7,17.5S11.71,28,17.5,28S28,23.29,28,17.5S23.29,7,17.5,7z M17.5,25c-4.136,0-7.5-3.364-7.5-7.5 c0-4.136,3.364-7.5,7.5-7.5c4.136,0,7.5,3.364,7.5,7.5C25,21.636,21.636,25,17.5,25z"></path>
</svg>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
version="1.1"
id="nightIcon"
x="0px"
y="0px"
viewBox="0 0 100 100"
style="enable-background:new 0 0 100 100"
xmlSpace="preserve"
aria-label={i18n(cfg.locale).components.themeToggle.lightMode}
>
<title>{i18n(cfg.locale).components.themeToggle.lightMode}</title>
<path
d="M96.76,66.458c-0.853-0.852-2.15-1.064-3.23-0.534c-6.063,2.991-12.858,4.571-19.655,4.571 C62.022,70.495,50.88,65.88,42.5,57.5C29.043,44.043,25.658,23.536,34.076,6.47c0.532-1.08,0.318-2.379-0.534-3.23 c-0.851-0.852-2.15-1.064-3.23-0.534c-4.918,2.427-9.375,5.619-13.246,9.491c-9.447,9.447-14.65,22.008-14.65,35.369 c0,13.36,5.203,25.921,14.65,35.368s22.008,14.65,35.368,14.65c13.361,0,25.921-5.203,35.369-14.65 c3.872-3.871,7.064-8.328,9.491-13.246C97.826,68.608,97.611,67.309,96.76,66.458z"></path>
</svg>
<div className="text-container">
<a>Light/Dark</a>
</div>
</button>
</div>
</div>
)
}
About.beforeDOMLoaded = darkmodeScript
About.css = styles
export default (() => About) satisfies QuartzComponentConstructor
b.quartz/components/styles/about.scss
// div
.about {
position: absolute;
bottom: 0.8rem;
left: 0;
right: 0;
}
// link
.link-container {
text-align: left;
opacity: 0.7;
margin-bottom: 0.6rem;
ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: row;
gap: 1rem;
margin-top: -1rem;
li a {
text-decoration: none;
color: #4584a5;
&:hover {
opacity: 0.7;
}
}
}
}
// home
.home-container {
display: flex;
align-items: center;
justify-content: flex-start;
}
// about
.about-container {
margin-bottom: 2px;
margin-right: 25px;
a {
text-decoration: none;
color: #7B97AA;
&:hover {
opacity: 0.7;
}
}
}
// changemode
.changemode {
cursor: pointer;
padding: 0;
position: relative;
background: none;
border: none;
width: 100px;
height: 30px;
margin-left: 2px;
margin-top: -6px;
text-align: inherit;
display: flex;
align-items: center; /* 垂直居中对齐 */
justify-content: flex-start; /* 水平左对齐,也可以根据需求调整 */
& svg {
position: absolute;
width: 20px;
height: 20px;
top: calc(50% - 10px);
fill: var(--darkgray);
transition: opacity 0.1s ease;
}
}
:root[saved-theme="dark"] {
color-scheme: dark;
}
:root[saved-theme="light"] {
color-scheme: light;
}
:root[saved-theme="dark"] .changemode {
& > #dayIcon {
display: none;
}
& > #nightIcon {
display: inline;
}
}
:root .changemode {
& > #dayIcon {
display: inline;
}
& > #nightIcon {
display: none;
}
}
// text
.text-container {
margin-bottom: -5px;
margin-left: 22px;
a {
font-size: 14px;
color: #7B97AA;
&:hover {
opacity: 0.7;
}
}
}
c.quartz/components/scripts/darkmode.inline.ts
const userPref = window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark"
const currentTheme = localStorage.getItem("theme") ?? userPref
document.documentElement.setAttribute("saved-theme", currentTheme)
const emitThemeChangeEvent = (theme: "light" | "dark") => {
const event: CustomEventMap["themechange"] = new CustomEvent("themechange", {
detail: { theme },
})
document.dispatchEvent(event)
}
document.addEventListener("nav", () => {
const switchTheme = (e: Event) => {
const newTheme =
document.documentElement.getAttribute("saved-theme") === "dark" ? "light" : "dark"
document.documentElement.setAttribute("saved-theme", newTheme)
localStorage.setItem("theme", newTheme)
emitThemeChangeEvent(newTheme)
}
const themeChange = (e: MediaQueryListEvent) => {
const newTheme = e.matches ? "dark" : "light"
document.documentElement.setAttribute("saved-theme", newTheme)
localStorage.setItem("theme", newTheme)
emitThemeChangeEvent(newTheme)
}
// Darkmode toggle
const themeButton = document.querySelector("#darkmode") as HTMLButtonElement
themeButton.addEventListener("click", switchTheme)
window.addCleanup(() => themeButton.removeEventListener("click", switchTheme))
// Changemode toggle
const themeButton2 = document.querySelector("#changemode") as HTMLButtonElement
themeButton2.addEventListener("click", switchTheme)
window.addCleanup(() => themeButton2.removeEventListener("click", switchTheme))
// Listen for changes in prefers-color-scheme
const colorSchemeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)")
colorSchemeMediaQuery.addEventListener("change", themeChange)
window.addCleanup(() => colorSchemeMediaQuery.removeEventListener("change", themeChange))
})
h.备案
a.quartz/components/Footer.tsx
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
import style from "./styles/footer.scss"
import { version } from "../../package.json"
import { i18n } from "../i18n"
interface Options {
links: Record<string, string>
}
export default ((opts?: Options) => {
const Footer: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => {
const year = new Date().getFullYear()
const links = opts?.links ?? []
return (
<footer class={`${displayClass ?? ""}`}>
<p>
{i18n(cfg.locale).components.footer.createdWith}{" "}
<a href="https://github.com/halavah">halavah</a> © {year}
</p>
<p>
苏ICP备19059396号-1
</p>
<ul>
{Object.entries(links).map(([text, link]) => (
<li>
<a href={link}>{text}</a>
</li>
))}
</ul>
</footer>
)
}
Footer.css = style
return Footer
}) satisfies QuartzComponentConstructor
b.quartz/components/styles/footer.scss
footer {
text-align: left;
margin-bottom: 1rem;
opacity: 0.7;
& ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: row;
gap: 1rem;
margin-top: -1rem;
}
}
03.启动锁【v1,代码不小心已丢弃】【最简单版本】【123456出现在html】
a.提问
你思考的方向有问题,目前 http://localhost:8080/verify 访问 还是处于 verify.md文件,而且是 内嵌在博客 布局(左边 explorer、右边大纲)里面,虽然verify.html存在,但并不是 @Verify.tsx 定义的 html。
重新思考你的修改方向,然后把多种思路汇报给我。不要生成任何代码
再对 你目前 对项目 所有改动的地方,对 verify 功能 进行检查
你对之前的全部提问,去真正理解我想干什么
先慢修改任何文件,你确定你写的 verifyPage.ts 最终可以生成我想要的 verify.html 页面,然后 http://localhost:8080/verify 可以路由到这个 验证页面吗
现在功能是可以使用的。针对 启动保护页面 功能,现在对你 项目修改的全部文件 进行检查,将不属于这个功能的 冗余代码、文件 进行删除
现在功能是可以使用的。再对 你目前 对项目 所有改动的地方,进行汇报
现在密码是123456,帮我创建100个随机密码,放到页面中。密码长度为10,允许强密码
-----------------------------------------------------------------------------------------------------
布局替换方向:
问题:当前的布局系统是基于 markdown 内容的,即使修改了 layout,仍然会套用基础布局
思路:需要在更底层处理布局,而不是仅仅修改 layout 配置
路由拦截方向:
问题:现在的路由处理是先找到 markdown 文件,然后应用布局
思路:在路由层面拦截 /verify 请求,直接返回 Verify 组件渲染的内容,绕过 markdown 处理流程
组件渲染方向:
问题:Verify.tsx 组件没有被正确地作为独立页面处理
思路:创建一个专门的页面渲染器,用于处理特殊路由的组件渲染
构建流程方向:
问题:构建过程将所有 markdown 文件视为相同类型的内容
思路:在构建时区分特殊页面,使用不同的构建流程
插件系统方向:
问题:当前的插件系统主要处理 markdown 内容
思路:创建新的插件类型,专门处理特殊页面的渲染
-----------------------------------------------------------------------------------------------------
verifyPage.ts分析:
优点:
完全独立的页面
不依赖博客布局
包含所有必要的样式和脚本
符合路由拦截的思路
b.方案2:路由拦截方向
1.访问任意页面
↓
2.Content.tsx 检查验证状态
↓
3.未验证则重定向到 /verify
↓
4.handlers.js 拦截 /verify 请求
↓
5.返回 verifyPage.ts 生成的页面
↓
6.用户输入密码 (123456)
↓
7.验证成功后重定向回原页面
c.quartz/cli/handlers.js - 路由处理改动
// 添加了验证页面路由处理
if (fp === "/verify") {
try {
const { generateVerifyPage } = await import("../../quartz/.quartz-cache/verify-page.js")
res.writeHead(200, { "Content-Type": "text/html" })
res.end(generateVerifyPage())
return
} catch (err) {
console.error("Error serving verify page:", err)
res.writeHead(500)
res.end("Internal Server Error")
return
}
}
d.quartz/build.ts - 构建配置改动
// 添加了 buildVerifyPage 函数
async function buildVerifyPage() {
try {
await esbuild.build({
entryPoints: ['./quartz/util/verifyPage.ts'],
outfile: './quartz/.quartz-cache/verify-page.js',
bundle: true,
format: 'esm',
platform: 'node',
})
console.log('Verify page built successfully')
} catch (err) {
console.error('Error building verify page:', err)
}
}
// 在 buildQuartz 函数中添加了构建验证页面的调用
await buildVerifyPage()
e.quartz/components/pages/Content.tsx - 添加验证脚本
// 添加了验证检查脚本
const verifyScript = `
if(!sessionStorage.getItem('verified')) {
const currentPath = window.location.pathname
if(currentPath !== '/verify') {
sessionStorage.setItem('intendedPath', currentPath)
window.location.href = '/verify'
}
}
`
Content.beforeDOMLoaded = verifyScript
f.新增文件 quartz/util/verifyPage.ts:
export function generateVerifyPage(): string {
const backgroundImages = [
"/static/screen/01.jpg",
"/static/screen/02.jpg",
"/static/screen/03.jpg",
"/static/screen/04.jpg",
"/static/screen/05.jpg",
"/static/screen/06.jpg",
"/static/screen/07.jpg",
]
const randomBackground = backgroundImages[Math.floor(Math.random() * backgroundImages.length)]
const verifyStyles = `
:root {
--primary: #4a90e2;
--secondary: #f5a623;
--background: rgba(240, 244, 248, 0.8);
--text: #333;
--error: #e74c3c;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: var(--text);
line-height: 1.6;
overflow: hidden;
}
.background-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('${randomBackground}');
background-size: cover;
background-position: center;
transform: scale(1.1);
z-index: -1;
}
.verify-page {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
perspective: 1000px;
}
.verify-container {
background-color: var(--background);
padding: clamp(20px, 5vw, 40px);
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
text-align: center;
max-width: min(90vw, 350px);
width: 100%;
backdrop-filter: blur(1px);
transform-style: preserve-3d;
animation: container-entrance 0.6s ease-out;
margin: 0 auto;
}
@keyframes container-entrance {
from {
opacity: 0;
transform: translateY(-50px) rotateX(10deg);
}
to {
opacity: 1;
transform: translateY(0) rotateX(0);
}
}
.lock-icon {
width: clamp(40px, 8vw, 50px);
height: clamp(40px, 8vw, 50px);
margin: 0 auto 15px;
color: var(--primary);
animation: icon-bounce 0.5s ease-out 0.3s both;
}
@keyframes icon-bounce {
0% {
transform: scale(0);
}
50% {
transform: scale(1.2);
}
100% {
transform: scale(1);
}
}
h1 {
color: var(--primary);
margin-bottom: 8px;
font-size: clamp(20px, 4vw, 24px);
animation: text-fade-in 0.5s ease-out 0.5s both;
}
p {
color: #666;
margin-bottom: 15px;
font-size: clamp(12px, 3vw, 14px);
animation: text-fade-in 0.5s ease-out 0.7s both;
}
@keyframes text-fade-in {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.input-group {
position: relative;
margin-bottom: 15px;
animation: input-fade-in 0.5s ease-out 0.9s both;
}
@keyframes input-fade-in {
from {
opacity: 0;
transform: translateX(-10px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
input {
width: 100%;
padding: clamp(8px, 2vw, 10px);
border: 2px solid #ddd;
border-radius: 4px;
font-size: clamp(14px, 3vw, 16px);
transition: border-color 0.3s, box-shadow 0.3s;
}
input:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
}
label {
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
color: #999;
pointer-events: none;
transition: 0.3s ease all;
font-size: clamp(12px, 2.5vw, 14px);
}
input:focus ~ label,
input:not(:placeholder-shown) ~ label {
top: 0;
font-size: 12px;
color: var(--primary);
background-color: white;
padding: 0 5px;
}
button {
background-color: var(--primary);
color: white;
border: none;
padding: clamp(8px, 2vw, 12px) clamp(15px, 4vw, 20px);
border-radius: 4px;
font-size: clamp(14px, 3vw, 16px);
cursor: pointer;
transition: background-color 0.3s, transform 0.3s;
width: 100%;
animation: button-fade-in 0.5s ease-out 1.1s both;
}
@keyframes button-fade-in {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
button:hover {
background-color: #3a7bc8;
transform: translateY(-2px);
}
button:active {
transform: translateY(0);
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
20%, 40%, 60%, 80% { transform: translateX(5px); }
}
.error {
border-color: var(--error) !important;
animation: shake 0.5s;
}
.error-message {
color: var(--error);
font-size: 14px;
margin-top: 5px;
display: none;
animation: error-fade-in 0.3s ease-out;
}
@keyframes error-fade-in {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (max-width: 480px) {
.verify-page {
padding: 10px;
}
.verify-container {
padding: 20px;
}
.background-container {
transform: scale(1.05);
}
}
`
const verifyScript = `
window.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('verify-form');
const passwordInput = document.getElementById('verify-password');
const verifyContainer = document.querySelector('.verify-container');
// 400个随机强密码
const validPasswords = [
"123456",
];
if (!sessionStorage.getItem('verified')) {
if (window.location.pathname !== '/verify') {
window.location.href = '/verify';
}
}
form?.addEventListener('submit', (e) => {
e.preventDefault();
const password = passwordInput.value;
if (validPasswords.includes(password)) {
sessionStorage.setItem('verified', 'true');
const intendedPath = sessionStorage.getItem('intendedPath') || '/';
window.location.href = intendedPath;
} else {
passwordInput.classList.add('error');
const errorMessage = document.createElement('div');
errorMessage.className = 'error-message';
errorMessage.textContent = 'Incorrect password. Please try again.';
form.appendChild(errorMessage);
errorMessage.style.display = 'block';
setTimeout(() => {
passwordInput.classList.remove('error');
errorMessage.style.display = 'none';
}, 3000);
}
});
passwordInput?.addEventListener('input', () => {
passwordInput.classList.remove('error');
const errorMessage = form.querySelector('.error-message');
if (errorMessage) {
errorMessage.style.display = 'none';
}
});
// Mouse movement effect
document.addEventListener('mousemove', (e) => {
const { clientX, clientY } = e;
const centerX = window.innerWidth / 2;
const centerY = window.innerHeight / 2;
const moveX = (clientX - centerX) / centerX;
const moveY = (clientY - centerY) / centerY;
verifyContainer.style.transform = \`
perspective(1000px)
rotateY(\${moveX * 5}deg)
rotateX(\${-moveY * 5}deg)
translateZ(10px)
\`;
});
});
`
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Verify Page</title>
<style>
${verifyStyles}
</style>
</head>
<body>
<div class="background-container">
<div class="verify-page">
<div class="verify-container">
<div class="lock-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg>
</div>
<h1>Welcome</h1>
<p>Life drifts untethered, fleeting as a dream.</p>
<form id="verify-form">
<div class="input-group">
<input type="password" id="verify-password" autofocus required>
<label for="verify-password">Password</label>
</div>
<button type="submit">Verify</button>
</form>
</div>
</div>
</div>
<script>
${verifyScript}
</script>
</body>
</html>
`.trim()
}
04.启动锁【v3_仅适配域名_如vercel_不可逆加密】
a.思路
1.访问任意页面
↓
2.Content.tsx 检查验证状态
↓
3.未验证则重定向到 /verify
↓
4.handlers.js 拦截 /verify 请求
↓
5.返回 verifyPage.ts 生成的页面,verify.html
↓
6.用户输入密码 (123456)
↓
7.验证成功后重定向回原页面
b.方案
Token 基于时间验证
不直接存储 verified: true,而是存储一个基于密码和时间生成的token
验证时同时验证token的有效性和时间戳
缺点:仍然可以被复制token绕过,但增加了难度
-----------------------------------------------------------------------------------------------------
多层验证令牌
将验证状态分成多个部分存储
每个部分都是通过密码+随机盐值生成的hash
需要所有部分都验证通过才能访问
缺点:技术人员仍可以通过分析代码找到生成规则
-----------------------------------------------------------------------------------------------------
动态验证码
基于密码和时间戳动态生成验证码
定期检查验证码是否有效
如果验证码过期需要重新验证
缺点:增加了复杂度,可能影响用户体验
-----------------------------------------------------------------------------------------------------
浏览器指纹 + 验证信息绑定
将验证信息与浏览器指纹绑定
即使复制storage也无法在其他浏览器使用
缺点:指纹可能变化,导致误判
-----------------------------------------------------------------------------------------------------
混淆与加密存储
不直接存储验证状态
将验证信息加密后分散存储在不同位置
使用复杂的验证逻辑
缺点:增加代码复杂度,仍可被破解
-----------------------------------------------------------------------------------------------------
需要注意的是,纯前端的安全方案都存在被破解的可能性,因为所有代码都在客户端。如果需要更高的安全性,建议:
考虑使用后端验证
使用 HTTPS 确保传输安全
实现访问频率限制
-----------------------------------------------------------------------------------------------------
考虑添加其他验证方式(如邮箱验证码)
c.采用
根据您的项目结构和需求,我建议采用"Token 基于时间验证"和"混淆与加密存储"的组合方案,因为:
实现相对简单
不需要额外的后端支持
可以在现有代码基础上扩展
性能影响较小
提供足够的安全性
比单纯的 sessionStorage.setItem('verified', 'true') 更安全
增加破解难度
可以设置token过期时间
-----------------------------------------------------------------------------------------------------
验证成功后:
// 不要直接存储 verified: true
// 而是生成一个包含以下信息的token:
- 时间戳
- 密码的hash值
- 随机盐值
存储方式:
// 将验证信息分散存储
- localStorage 存储一部分
- sessionStorage 存储另一部分
- cookie 存储第三部分
验证逻辑:
// 定期检查:
- token是否完整
- 时间戳是否有效
- hash值是否匹配
-----------------------------------------------------------------------------------------------------
这样即使有人知道需要设置storage,也很难知道:
具体需要设置什么值
值是如何生成的
需要在哪些地方设置
d.实现
验证流程:
Content.tsx 中的 verifyScript 在每个页面加载时检查 sessionStorage.getItem('verified')
未验证时保存当前路径到 intendedPath 并重定向到 /verify
handlers.js 处理 /verify 路由,返回验证页面
-----------------------------------------------------------------------------------------------------
关键问题:
目前的验证状态只依赖 sessionStorage.setItem('verified', 'true')
这个状态很容易被手动设置绕过验证
-----------------------------------------------------------------------------------------------------
改进思路:
// 验证成功时:
const generateToken = (password: string) => {
const timestamp = Date.now()
const salt = crypto.randomBytes(16).toString('hex')
// 1. 生成一个包含密码hash、时间戳和salt的token
const rawToken = `${hash(password)}:${timestamp}:${salt}`
// 2. 对token进行加密
const encryptedToken = encrypt(rawToken)
// 3. 分散存储token的不同部分
const [part1, part2, part3] = splitToken(encryptedToken)
sessionStorage.setItem('v_p1', part1)
localStorage.setItem('v_p2', part2)
document.cookie = `v_p3=${part3}`
return true
}
// 验证检查时:
const checkVerification = () => {
try {
// 1. 收集所有部分
const part1 = sessionStorage.getItem('v_p1')
const part2 = localStorage.getItem('v_p2')
const part3 = getCookie('v_p3')
// 2. 重组并解密token
const token = decrypt(joinToken(part1, part2, part3))
// 3. 验证时间戳是否在有效期内
const [hash, timestamp, salt] = token.split(':')
if (Date.now() - parseInt(timestamp) > TOKEN_EXPIRE_TIME) {
return false
}
// 4. 验证hash是否正确
return verifyHash(hash)
} catch {
return false
}
}
-----------------------------------------------------------------------------------------------------
不能简单通过设置 storage 绕过
token 有时效性
验证信息分散存储
即使找到存储位置也很难伪造正确的token
e.BUG:闪一下
不要生成任何代码,为什么 访问 @http://127.0.0.1:8080 会闪一下,然后才跳转 @http://127.0.0.1:8080/verify
-----------------------------------------------------------------------------------------------------
将验证脚本移到 <head> 标签中
使用 defer 或 async 属性
在 DOMContentLoaded 之前执行验证
f.混淆加密(可逆向)
当前的加密数据和盐值都是明文存储的
可以将数据分散存储并引入干扰数据
实现相对简单,不会增加太多复杂度
-----------------------------------------------------------------------------------------------------
将加密数据分散存储在多个变量或对象中
使用字符串编码转换(如Base64、Unicode转换等)
引入干扰数据,真实数据藏在其中
使用多层加密,每层使用不同的算法
-----------------------------------------------------------------------------------------------------
当前的问题
const AUTH = {
SALT: "x9f#k2p$m5",
DATA: "HFUMVxJWH1MDBAABWBlGA0sSUARNFRISWBlGA0sSUAQ="
}
盐值直接明文存储
加密数据使用单一Base64编码
数据结构过于简单直观
-----------------------------------------------------------------------------------------------------
改进思路
A.数据分散存储:
将SALT拆分成多段,分散在不同变量中
使用动态计算组合真实盐值
加入虚假的盐值干扰项
B.多重编码:
Base64 -> Unicode -> Hex 多层转换
字符串反转或位移
添加动态位移量
C.干扰数据:
在加密数据中插入随机干扰字符
使用特定规则来提取真实数据
构建虚假的验证路径
D.数据存储结构:
使用嵌套对象
引入无关的配置数据
使用动态计算的属性名
g.简单加密(可逆向)
a.思路
1.后端验证方案
这是最推荐的方案,将密码验证逻辑完全移到后端:
前端只发送密码到后端API
后端进行验证并返回token
使用session或JWT来保持登录状态
2.密码加密方案
如果必须在前端做验证,可以:
存储密码的哈希值而不是明文
对用户输入进行相同的哈希处理后比较
使用加盐哈希增加安全性
3.混淆加密方案
通过代码混淆和加密来增加破解难度:
使用JavaScript混淆器处理代码
将密码列表进行加密存储
运行时动态解密
b.采用【混淆加密方案】,加密过程是:
每个密码先填充到32字符长度
使用XOR(异或)运算加密每个字符:
密码字符 XOR 密钥字符
密钥是 salt("x9f#k2p$m5") + 当天日期
将所有加密后的字符串拼接
最后用base64编码整个结果
c.解密方法
function encryptPasswords(passwords: string[], salt: string): string {
const key = salt + new Date().getUTCDate()
const data = passwords
.map((pwd) => {
return pwd
.padEnd(32, " ")
.split("")
.map((char, index) => {
return String.fromCharCode(char.charCodeAt(0) ^ key.charCodeAt(index % key.length))
})
.join("")
})
.join("")
return btoa(data)
}
h.只能正向加密(采用)
生成的密码 只能是正向的,不能是逆向的。
而验证时,只能根据输入的密码来正向,最后比较2个最终的结果(比较方式,经过加密)
05.启动锁【废弃】,自动适配【域名】【域名/仓库】
a.提问
让我重新梳理思路:
当前问题:
访问根路径时出现 302 重定向
验证成功后无法正确跳转回原始路径
路径处理在不同环境下不一致
可能的解决思路:
思路A - 纯前端处理:
在 Content.tsx 中检测未验证状态
保存当前路径到 sessionStorage
重定向到验证页面
验证成功后从 sessionStorage 读取路径并跳转
思路B - 服务端重定向:
在 handlers.js 中拦截所有请求
未验证时重定向到验证页面
通过 URL 参数传递原始路径
验证成功后从 URL 参数获取跳转路径
思路C - 混合处理:
服务端处理根路径访问的重定向
前端处理其他页面的验证检查
统一使用 sessionStorage 存储路径
验证页面同时支持 URL 参数和 sessionStorage
各思路的优缺点:
思路A:
优点:实现简单,完全前端控制
缺点:可能出现闪烁,安全性较低
思路B:
优点:更安全,体验更流畅
缺点:实现复杂,需要处理多种路径情况
思路C:
优点:兼顾安全性和用户体验
缺点:逻辑分散,需要同步前后端状态
你觉得哪个思路更适合?我可以详细展开任何一个思路。
-----------------------------------------------------------------------------------------------------
问题所在:
sessionStorage 是前端存储
服务端(handlers.js)无法访问 sessionStorage
导致每次请求服务端都会认为是未验证状态
结果就是不断302重定向
验证流程:
用户访问 http://127.0.0.1:8080/
handlers.js 检查验证状态(但无法访问 sessionStorage)
重定向到 /verify?from=/
即使验证成功存储在 sessionStorage
下次请求时服务端仍然无法知道验证状态
继续重定向...形成循环
所以思路B不可行,应该回到思路A或C:
思路A(纯前端)更合理:
1. 所有验证逻辑在前端处理
Content.tsx 检查 sessionStorage
未验证则保存路径并重定向
4. 验证成功后直接从 sessionStorage 恢复路径
这样避免了服务端重定向的问题,你觉得呢?
-----------------------------------------------------------------------------------------------------
// 对于 https://halavah.github.io/valut/verify
// pathParts = ['valut', 'verify']
// lastPath = 'verify'
// repoPath = 'valut'
// finalBasePath = '/valut'
// 对于 https://valut.vercel.app/verify
// pathParts = ['verify']
// lastPath = 'verify'
// repoPath = ''
// finalBasePath = ''
const pathParts = window.location.pathname.split('/').filter(Boolean)
const lastPath = pathParts[pathParts.length - 1]
const isVerifyPage = lastPath === 'verify'
const repoPath = isVerifyPage && pathParts.length > 1 ? pathParts[pathParts.length - 2] : ''
const finalBasePath = repoPath ? '/' + repoPath : ''
访问 https://halavah.github.io/valut/ 跳转 https://halavah.github.io/valut/verify ,然后通过verify.html来验证
访问 https://halavah.github.io 跳转 https://halavah.github.io/verify ,然后通过verify.html来验证
访问 https://valut.vercel.app 跳转 https://valut.vercel.app/verify ,然后通过verify.html来验证
访问 http://127.0.0.1:8080 跳转 http://127.0.0.1:8080/verify ,然后通过verify.html来验证
b.实现
放弃
5.5 quartz2
01.使用
a.下载
npx shadcn@latest add "https://v0.dev/chat/b/b_4X2vSJZ3iRk"
b.安装
npm install
c.使用
npm run dev --开发环境:启动
-----------------------------------------------------------------------------------------------------
npm run build --生产环境:构建
npm run start --生产环境:启动
02.启动锁【Next.js后端服务】
a.需求
auth.ts 中需要移至后端的部分:
密码加密函数 _encrypt
密码哈希值 correctHashes
Token 生成逻辑 generateToken
Token 验证逻辑 verifyToken
-----------------------------------------------------------------------------------------------------
verifyPage.ts 中需要移至后端的部分:
验证页面生成函数 generateVerifyPage
页面模板可以转换为 Next.js 的页面组件
-----------------------------------------------------------------------------------------------------
Content.tsx 中需要移至后端的部分:
验证状态检查逻辑
b.认证相关 API
POST /api/auth/verify
- 功能:验证密码
- 输入:password
- 返回:token
GET /api/auth/check
- 功能:验证 token
- 输入:token (从 cookie)
- 返回:验证状态
POST /api/auth/logout
- 功能:登出
- 输入:token
- 返回:成功状态
c.页面路由
/verify
- 登录页面
- 使用 Next.js 页面组件
- 包含表单和样式
/api/protected/*
- 受保护的内容 API
- 需要验证 token
d.中间件
middleware.ts
- 路由保护
- token 验证
- 重定向逻辑
03.启动锁【Next.js后端服务】【思路1】
a.当前思路
用户访问 Quartz 页面
↓
Content.tsx 检查验证状态(调用 Next.js API)
↓
未验证则重定向到 Next.js 验证页面
↓
用户输入密码
↓
Next.js 后端验证
↓
验证成功返回 Quartz
b.创建 Next.js 验证服务
quartz-auth/ # Next.js 项目根目录
├── pages/
│ ├── api/ # API 路由
│ │ └── auth/ # 认证相关 API
│ │ ├── verify # 密码验证
│ │ ├── check # token 检查
│ │ └── logout # 登出
│ └── verify.tsx # 验证页面
└── middleware.ts # 路由中间件
c.修改现有 Quartz 代码
quartz-front/quartz/util/verifyPage.ts # 整个文件移除
quartz-front/public/verify.html # 由 Next.js 的 verify.tsx 替代
quartz-front/quartz/util/auth.ts # 移除,逻辑移至 Next.js
d.需要修改
quartz-front/quartz/components/pages/Content.tsx
# 修改验证逻辑,改为调用 Next.js API
e.数据和资源迁移
quartz-front/public/static/screen/* # 背景图片迁移到 Next.js
quartz-front/public/static/icon.png # 图标迁移到 Next.js
f.配置更新
设置 Next.js 服务的域名和端口
配置 CORS 策略
设置环境变量
g.部署流程
部署 Next.js 服务到 Vercel
更新 Quartz 配置指向新的验证服务
确保域名和 SSL 证书配置正确
04.启动锁【Next.js后端服务】【思路2】
a.当前思路
用户访问 Quartz 页面
↓
Content.tsx 检查验证状态(调用 Next.js API)
↓
未验证则重定向到 Next.js 验证页面
↓
用户输入密码
↓
Next.js 后端验证
↓
验证成功返回 Quartz
b.密码验证接口(同时会生成令牌)
curl --location 'http://localhost:3000/api/auth?action=verify' \
--header 'Content-Type: application/json' \
--data '{
"password": "123456"
}'
-----------------------------------------------------------------------------------------------------
成功响应示例:
{
"success": true,
"tokens": {
"session": "TUI5OEly", // 存储到 sessionStorage
"local": "MzNDU2Nz" // 存储到 localStorage
}
// cookie 部分会自动设置到浏览器(v_p3=g5MDphYm)
}
-----------------------------------------------------------------------------------------------------
前端调用示例:
async function verifyPassword(password: string) {
const response = await fetch('/api/auth?action=verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ password }),
credentials: 'include', // 重要:允许设置cookie
})
const data = await response.json()
if (data.success) {
// 存储令牌的两个部分
sessionStorage.setItem(AUTH_CONSTANTS.TOKEN_KEYS.SESSION, data.tokens.session)
localStorage.setItem(AUTH_CONSTANTS.TOKEN_KEYS.LOCAL, data.tokens.local)
// cookie部分已自动设置
return true
}
return false
}
c.令牌检查接口
curl --location 'http://localhost:3000/api/auth?action=check&session=TUI5OEly&local=MzNDU2Nz' \
--header 'Cookie: v_p3=g5MDphYm'
-----------------------------------------------------------------------------------------------------
响应示例:
{
"isAuthenticated": true
}
-----------------------------------------------------------------------------------------------------
前端调用示例:
async function checkAuth() {
const session = sessionStorage.getItem(AUTH_CONSTANTS.TOKEN_KEYS.SESSION)
const local = localStorage.getItem(AUTH_CONSTANTS.TOKEN_KEYS.LOCAL)
if (!session || !local) return false
const response = await fetch(
`/api/auth?action=check&session=${encodeURIComponent(session)}&local=${encodeURIComponent(local)}`,
{
credentials: 'include', // 重要:允许发送cookie
}
)
const data = await response.json()
return data.isAuthenticated
}
d.防止前端 JS 被篡改的几个思路:
服务端验证为主
所有关键验证逻辑都放在服务端
前端验证只作为用户体验的补充
服务端不信任任何前端传来的数据
-----------------------------------------------------------------------------------------------------
代码混淆和加密
使用工具对 JS 代码进行混淆
关键逻辑使用加密方式存储
动态解密执行关键代码
-----------------------------------------------------------------------------------------------------
完整性校验
计算 JS 文件的哈希值
服务端验证文件完整性
使用 SRI (Subresource Integrity) 属性
-----------------------------------------------------------------------------------------------------
动态代码注入
核心验证逻辑由服务端动态生成
每次请求生成不同的验证代码
使用一次性的验证令牌
-----------------------------------------------------------------------------------------------------
环境检测
检测开发者工具是否打开
检测代码是否被修改
检测运行环境的合法性
-----------------------------------------------------------------------------------------------------
多重验证机制
多层验证逻辑组合
验证步骤之间相互依赖
使用多个加密密钥
-----------------------------------------------------------------------------------------------------
时间戳和有效期
验证代码包含时间限制
定期更新验证逻辑
使用一次性的验证码
-----------------------------------------------------------------------------------------------------
请求签名
对关键请求进行签名
验证请求的来源和完整性
使用 HMAC 等算法
-----------------------------------------------------------------------------------------------------
行为分析
分析用户操作行为
检测异常的请求模式
建立风险控制机制
-----------------------------------------------------------------------------------------------------
硬件绑定
绑定特定的硬件特征
使用硬件级别的加密
验证设备指纹
e.存储对比
sessionStorage:
每次打开新标签页都会重置
仅在当前标签页有效
关闭标签页后数据就会消失
所以 v_p1 确实会在新标签页中重置
-----------------------------------------------------------------------------------------------------
localStorage:
数据会永久保存
在所有标签页中共享
除非手动清除,否则数据会一直存在
所以 v_p2 和 v_p3 不会重置
5.6 quartz3
01.网站加速,halavah.us,github -> vercel -> cloudflare -> cdn(vercel.cdn.yt-blog.top)
a.汇总
a.DNS说明
记录类型 解释
A 用来指定域名的 IPv4 地址(如 8.8.8.8),如果需要将域名指向一个 IP 地址,就需要添加 A 记录。
CNAME 如果需要将域名指向另一个域名,再由另一个域名提供 IP 地址,就需要添加 CNAME 记录。
MX 如果需要设置邮箱,让邮箱能收到邮件,就需要添加 MX 记录。
TXT 在这里可以填写任何东西,长度限制 255。绝大多数的 TXT 记录是用来做 SPF 记录(反垃圾邮件)
NS 域名服务器记录,如果需要将子域名交给其他 DNS 服务商解析,就需要添加 NS 记录。
AAAA 用来指定主机名(或域名)对应的 IPv6 地址(例如:ff06:0:0:0:0:0:0:c3)记录。
SRV 记录了哪台计算机提供了哪个服务。格式为:服务的名字、点、协议的类型,例如:_xmpp-server_tcp。
显性URL 从一个地址 301 重定向到另一个地址的时候,就需要添加显性 URL 记录(注:DNSPod 目前只支持 301 重定向)。
隐性URL 类似于显性 URL,区别在于隐性 URL 不会改变地址栏的域名。
b.HTTPS爆红
当你访问一个 HTTPS URL(例如 https://172.17.10.80/)时,如果浏览器显示“爆红”警告(通常是一个红色的警告页面),这通常是因为存在以下几种常见的 SSL/TLS 证书问题:
自签名证书:服务器使用的是自签名证书,而不是由受信任的证书颁发机构(CA)签发的证书。浏览器默认不信任自签名证书,因此会显示警告。
证书过期:服务器的 SSL/TLS 证书已经过期。证书有一个有效期,如果超过了这个有效期,浏览器会认为证书不再安全。
证书不匹配:证书的域名与访问的域名不匹配。例如,证书是为 example.com 签发的,但你访问的是 172.17.10.80。这种情况下,浏览器会认为证书不可信。
证书被吊销:证书被证书颁发机构吊销。浏览器会检查证书的吊销状态,如果证书被吊销,浏览器会显示警告。
证书链问题:证书链不完整或不正确。浏览器需要验证证书链中的所有证书,如果链中的任何一个证书无效或缺失,浏览器会显示警告。
c.注意事项
IP证书
邮件服务器([email protected] )
域名解析跟DNS全球服务器有关系,和哪里来的域名没关系
b.vercel
a.添加二级域名
https://vercel.com/halavahs-projects/valut/settings/domains
valut.halavah.us
-----------------------------------------------------------------------------------------------------
CNAME (Recommended)
Nameservers
Set the following record on your DNS provider to continue:
Type Name Value
CNAME valut cname.vercel-dns.com.
b.域名解析地址
Vercel 官方默认线路:cname.vercel.com
Vercel 官方对大陆优化线路: cname-china.vercel-dns.com
Fgaoxing 提供针对 Vercel 优选的 DNS 线路:vercel.cdn.yt-blog.top
c.示例
一级域名 (example.com):
名称:@
类型:A
IP:1.2.3.4
-------------------------------------------------------------------------------------------------
二级域名 (blog.example.com):
名称:blog
类型:A
IP:1.2.3.4
-------------------------------------------------------------------------------------------------
泛解析 (*.example.com)
名称:*
类型:A
IP:1.2.3.4
c.CloudFlare
a.第1步:仅DNS,是为了通过DNS记录,来验证vercel
使用https://vercel.com/halavahs-projects/valut2/settings/domains查看解析情况
-------------------------------------------------------------------------------------------------
类型 名称 内容 TTL 代理状态
CNAME valut cname.vercel-dns.com. 仅DNS 自动
CNAME valut2 cname.vercel-dns.com. 仅DNS 自动
CNAME valut3 cname.vercel-dns.com. 仅DNS 自动
CNAME valut-end cname.vercel-dns.com. 仅DNS 自动
CNAME picgo cname.vercel-dns.com. 仅DNS 自动
b.第2步:使用Fgaoxing提供的DNS线路
类型 名称 内容 TTL 代理状态
CNAME valut vercel.cdn.yt-blog.top 仅DNS 自动
CNAME valut2 vercel.cdn.yt-blog.top 仅DNS 自动
CNAME valut3 vercel.cdn.yt-blog.top 仅DNS 自动
CNAME valut-end vercel.cdn.yt-blog.top 仅DNS 自动
CNAME picgo vercel.cdn.yt-blog.top 仅DNS 自动
c.第3步:开启CDN代理
类型 名称 内容 TTL 代理状态
CNAME valut vercel.cdn.yt-blog.top 已代理 自动
CNAME valut2 vercel.cdn.yt-blog.top 已代理 自动
CNAME valut3 vercel.cdn.yt-blog.top 已代理 自动
CNAME valut-end vercel.cdn.yt-blog.top 已代理 自动
CNAME picgo vercel.cdn.yt-blog.top 已代理 自动
-------------------------------------------------------------------------------------------------
SSL/TLS
完全(严格)
d.说明
如果使用 Cloudflare 代理(橙色云朵),需要在 Cloudflare 中专门设置端口转发
建议将代理状态设置为关闭(灰色云朵),这样可以直接访问原始端口
Cloudflare 免费版本只支持特定的端口(如 80、443 等),对于 28575 这样的非标准端口,需要关闭 Cloudflare 代理
d.访问
a.备案
【晋ICP备2025056343号】->quartz/util/verifyPage.ts
【苏ICP备19059396号-1】->quartz/components/Footer.tsx
b.链接
https://valut.halavah.us https://valut.vercel.app
https://valut2.halavah.us https://valut2.vercel.app
https://valut3.halavah.us https://valut3-sand.vercel.app
https://valut-end.halavah.us https://quartz-end.vercel.app
https://picgo.halavah.us https://picgo-pi.vercel.app
https://tree.halavah.us pintree-taupe-gamma.vercel.app
https://cursor-api.halavah.us https://cursor-api-halavahs-projects.vercel.app/
-------------------------------------------------------------------------------------------------
https://api.halavah.us
https://chat.halavah.us
https://nextra.halavah.us
c.链接
http://119.91.252.124:83/verify?token=troyekk
api.kafuchino.online
chat.kafuchino.online
test.kafuchino.online
valut.kafuchino.online
valut2.kafuchino.online
valut3.kafuchino.online
-------------------------------------------------------------------------------------------------
myslayers.top:2025-03-30至2035-03-30
api.myslayers.top
chat.myslayers.top
test.myslayers.top
valut.myslayers.top
valut2.myslayers.top
valut3.myslayers.top
-------------------------------------------------------------------------------------------------
ngrok.myslayers.top 100.64.0.8:48080
ngrok-ui.myslayers.top 100.64.0.8:83
-------------------------------------------------------------------------------------------------
nat.myslayers.top 100.64.0.8:48080
nat-ui.myslayers.top 100.64.0.8:83
02.日常维护
a.gihtub page
a.前提
必须仓库为公有public
b.不使用Action
settings -> pages -> Build and deployment -> Deploy from a branch -> master、/docs
c.使用Action
.github/workflows/deploy.yml,该文件指定构建目录,如public;指定构建分支,如master
settings -> pages -> Build and deployment -> GitHub Actions
GitHub Actions -> 查看构建情况
b.发布99.Directory01到valut
a.public
baseUrl: "halavah.github.io/valut",注意,不能设置为【halavah.github.io/99.Directory01】,有数字+小数点,会当作一个域
public必须上传,而且内容不能为空,否则空文件夹无法上次github
b.git上传前,必须生成public内容
start.bat(npx quartz build --serve)
git add . && git commit -m "my first commit" && git commit --amend -m "新的提交注释"
git push origin master
-------------------------------------------------------------------------------------------------
git tag v1.0 && git push origin v1.0
c.常用提交
git clone https://github.com/halavah/valut.git 99.Directory01
git clone https://github.com/halavah/valut2.git 99.Directory02
git clone https://github.com/halavah/valut3.git 99.Directory03
-------------------------------------------------------------------------------------------------
git add . && git commit -m "20241222"
git push origin master
-------------------------------------------------------------------------------------------------
git tag 20241222
git push origin 20241222
-------------------------------------------------------------------------------------------------
git tag
git tag -d 标签名
-------------------------------------------------------------------------------------------------
git branch --查看分支
git status --查看状态
git log --oneline --查看提交日志
git reset --soft HEAD"^" --返回上一个commit状态,并保留当前修改的文件
git push --force origin master --忽略远程版本,强制提交
d.定版提交
git add . && git commit -m "v9.1_正式版本"
git push origin master
git tag v9.1_正式版本
git push origin v9.1_正式版本
-------------------------------------------------------------------------------------------------
git add . && git commit -m "v9.2_校验nextjs适应国内外环境"
git push origin master
git tag v9.2_校验nextjs适应国内外环境
git push origin v9.2_校验nextjs适应国内外环境
-------------------------------------------------------------------------------------------------
git add . && git commit -m "v10_适应子模块,vercel线上编译"
git push origin master
git tag v10_适应子模块,vercel线上编译
git push origin v10_适应子模块,vercel线上编译
c.修改忽略文件
a.文件名:.gitignore
node_modules
.obsidian
.obsidian_android
.trash
_assets/
Chapter01/Quick.assets/
Chapter01/Ready.assets/
Chapter01/Remote.assets/
Chapter01/StartUp.assets/
Chapter02/Build.assets/
Chapter02/Deploy.assets/
Chapter02/Internet.assets/
Chapter03/Balance.assets/
Chapter03/Growth.assets/
Chapter03/Symbol.assets/
Chapter03/Traffic.assets/
b.将原先Chapter01/Quick.assets/脱离版本控制
git rm -r --cached "Chapter01/Quick.assets/"
git rm -r --cached "Chapter01/Ready.assets/"
git rm -r --cached "Chapter01/Remote.assets/"
git rm -r --cached "Chapter01/StartUp.assets/"
git rm -r --cached "Chapter02/Build.assets/"
git rm -r --cached "Chapter02/Deploy.assets/"
git rm -r --cached "Chapter02/Internet.assets/"
git rm -r --cached "Chapter03/Balance.assets/"
git rm -r --cached "Chapter03/Growth.assets/"
git rm -r --cached "Chapter03/Symbol.assets/"
git rm -r --cached "Chapter03/Traffic.assets/"
c.注意
.gitignore 添加 **/*.assets/ --失效
git rm -r --cached "**/*.assets/" --失效
03.vercel部署
a.普通部署content
a.Framework Preset
Other
b.Root Directory
空,代表根目录
c.BuildandOutputSettings
Build Command:npx quartz build --verbose
Output Directory:public
Install Command:npm install
Environment Command:空
d.EnvironmentVariables
空
b.以submodule子模块部署content
a.参考
https://stephenweiss.dev/vercel-private-submodules
b.根目录./gitmodules
[submodule "content"]
path = content
url = [email protected] :halavah/Directory01.git --以前是https://github.com/halavah/Directory01
c.git配置:.git/config
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true
[remote "origin"]
url = [email protected] :halavah/Directory01.git --以前是https://github.com/halavah/Directory01
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
rebase = true
d.package.json
"scripts": {
"quartz": "./quartz/bootstrap-cli.mjs",
"docs": "npx quartz build --serve -d docs",
"check": "tsc --noEmit && npx prettier . --check",
"format": "npx prettier . --write",
"test": "tsx ./quartz/util/path.test.ts && tsx ./quartz/depgraph.test.ts",
"profile": "0x -D prof ./quartz/bootstrap-cli.mjs build --concurrency=1"
"vercel-build": "chmod u+x ./vercel-submodule-workaround.sh && ./vercel-submodule-workaround.sh && npx quartz build --verbose"
},
e.vercel
a.Framework Preset
Other
b.Root Directory
空,代表根目录
c.BuildandOutputSettings
Build Command:npm run vercel-build
Output Directory:public
Install Command:npm install
Environment Command:空
d.EnvironmentVariables
GITHUB_ACCESS_TOKEN 对应 github的Token值
设置 -> 开发者设置 -> 个人访问令牌
生成新令牌
设置到期日期
确保检查 Repo 的完全访问权限:[x] repo - Full control of private repositories
f.vercel-submodule-workaround.sh
修改如下2点:
MAIN_REPO 主仓库
SUBMODULE_PATH 子模块项目路径,注意,不需要填写该 submodule子模块 具体项目路径,会自动读取 .gitmodules
-------------------------------------------------------------------------------------------------
# repo paths (supplied without the protocol prefix)
# 定义主项目仓库地址
MAIN_REPO=github.com/halavah/valut.git
# 定义子模块在项目中的路径
SUBMODULE_PATH=content
# 检查 Vercel 环境变量 VERCEL_GIT_COMMIT_SHA 是否为空
if [ "$VERCEL_GIT_COMMIT_SHA" == "" ]; then
echo "Error: VERCEL_GIT_COMMIT_SHA is empty"
exit 1
fi
# 检查 GITHUB_ACCESS_TOKEN 是否为空
if [ "$GITHUB_ACCESS_TOKEN" == "" ]; then
echo "Error: GITHUB_ACCESS_TOKEN is empty"
exit 1
fi
# 遇到错误时停止脚本执行
set -e
# 设置一个临时工作目录,并清理之前可能存在的临时文件夹
rm -rf vercel-tmp || true
mkdir vercel-tmp
cd vercel-tmp
# 初始化一个新的 Git 仓库
# 检出当前提交
git init
# 添加远程仓库地址并包含访问令牌
git remote add origin https://$GITHUB_ACCESS_TOKEN@$MAIN_REPO
# 获取指定提交的内容(深度为1以节省资源)
git fetch --depth=1 origin $VERCEL_GIT_COMMIT_SHA
# 检出指定提交
git checkout $VERCEL_GIT_COMMIT_SHA
# 修改 .gitmodules 文件中的子模块路径
# 将 SSH 路径替换为 HTTPS 路径,以便使用访问令牌访问子模块
mv .gitmodules .gitmodules.original
cat .gitmodules.original | sed "s/[email protected] :/https:\/\/[email protected] \//" > .gitmodules
# 同步子模块配置并初始化和更新子模块
# 使用 sed 隐藏日志中可能暴露的访问令牌
git submodule sync
git submodule update --init --recursive 2>&1 | sed "s/$GITHUB_ACCESS_TOKEN/\*\*\*\*/"
# 将子模块内容移动到主项目中定义的位置
cd ..
# 删除子模块中的 .git 文件夹(子模块本身是一个独立的 Git 仓库)
rm -rf vercel-tmp/$SUBMODULE_PATH/.git
# 如果子模块路径已经存在,则备份原来的内容
if [ -d $SUBMODULE_PATH ]; then
mv $SUBMODULE_PATH $SUBMODULE_PATH.original
fi
# 创建子模块目标路径的父目录
mkdir -p $(dirname $SUBMODULE_PATH)
# 将子模块移动到目标位置
mv vercel-tmp/$SUBMODULE_PATH/ $SUBMODULE_PATH
# 显示子模块路径的内容,以验证子模块是否被正确加载
ls -l $SUBMODULE_PATH
# 清理临时工作目录
rm -rf vercel-tmp
c.更新子仓库
cd content
git pull origin main # 或其他分支名称
git add . # 若有更改
git commit -m "Update content submodule"
04.更改submodule子模块
查看【startup -> submodule单向:实战操作(定)】
05.自动化脚本
a.参考
Quick.assets/9998.vercel 加载私有子模块1.htm
Quick.assets/9998.vercel 加载私有子模块2.png
-----------------------------------------------------------------------------------------------------
https://github.com/halavah/valut主仓库
https://github.com/halavah/Directory01 子仓库
[submodule "content"]
path = content
url = [email protected] :halavah/Directory01.git
现在 要求,https://github.com/halavah/Directory01 提交内容后,
https://github.com/halavah/valut 自动在 remote云端 更新最新内容
现在的脚本部署在 Directory01 子仓库上,
-----------------------------------------------------------------------------------------------------
Windows(CR LF)、Unix(LF)
b.子仓库,01.Directory01
a.github/workflows/update-main-repo.yml
name: Update Main Repo
on:
push:
branches:
- master
paths:
- '**'
jobs:
update-submodule:
runs-on: ubuntu-latest
steps:
- name: Checkout main repository
uses: actions/checkout@v3
with:
repository: halavah/valut --第1处
token: ${{ secrets.MY_GITHUB_TOKEN }}
fetch-depth: 0
- name: Configure Git
run: |
git config --global user.email "[email protected] "
git config --global user.name "myslayers"
# 将子模块 URL 改为 HTTPS 格式
git config --file=.gitmodules submodule.content.url https://${{ secrets.MY_GITHUB_TOKEN }}@github.com/halavah/Directory01.git --第2处
git submodule sync
- name: Update submodule
run: |
# 初始化并更新子模块
git submodule update --init --recursive
# 进入子模块目录并更新
cd content
git checkout master
git pull origin master
# 返回主仓库目录
cd ..
# 检查是否有更改
if git status | grep -q 'nothing to commit'; then
echo "No changes to commit"
exit 0
fi
# 提交更改
TIMESTAMP=$(date +'%Y%m%d_%H%M%S')
git add content
git commit -m "Update submodule reference at $TIMESTAMP"
git push https://${{ secrets.MY_GITHUB_TOKEN }}@github.com/halavah/valut.git HEAD:master --第3处
b.deploy.bat(无需更改)
@echo off
setlocal EnableDelayedExpansion
:: Navigate to the directory where the script is located
cd /d "%~dp0"
:: Stage all changes first
echo Staging all changes...
git add .
if !errorlevel! neq 0 (
echo Failed to stage changes.
pause
exit /b 1
)
:: Check if there are changes to commit
git diff --staged --quiet
if !errorlevel! equ 0 (
echo No changes to commit.
:: If no changes, just pull and exit
echo Pulling latest changes from origin/master...
git pull origin master
pause
exit /b 0
)
:: Commit changes with timestamped message
set "timestamp=%date:~0,4date:~8,2%_%time:~0,2time:~6,2%"
set "timestamp=!timestamp: =0!"
echo Committing changes with timestamp: !timestamp!...
git commit -m "!timestamp!"
if !errorlevel! neq 0 (
echo Failed to commit changes.
pause
exit /b 1
)
:: Pull latest changes from the remote repository
echo Pulling latest changes from origin/master...
git pull origin master
if !errorlevel! neq 0 (
echo Failed to pull changes. Resolve conflicts if any, and rerun the script.
pause
exit /b 1
)
:: Push changes to the repository
echo Pushing changes to origin/master...
git push origin master
if !errorlevel! neq 0 (
echo Failed to push changes.
pause
exit /b 1
)
echo Changes successfully pulled, committed, and pushed.
pause
exit /b 0
c.主仓库,99.Directory01
a.github/workflows/deploy.yml
name: Deploy Quartz site to GitHub Pages
on:
push:
branches:
- v4 --修改分支
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for git info
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install Dependencies
run: npm ci
- name: Build Quartz
run: npx quartz build
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: public --构建文件夹
deploy:
needs: build
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
b.deploy.bat(无需更改)
Deploy:
cd /d "%~dp0"
git add .
git diff --staged --quiet
git commit -m "!timestamp!"
git pull origin master
git submodule update --remote --merge
git push origin master
-------------------------------------------------------------------------------------------------
Build
cd /d "%~dp0content"
git pull origin master
cd /d "%~dp0"
del /q /f "public\*.*"
for /d i"
mkdir public
copy /y ".flag" "public\.flag"
npm install
call npx quartz build --verbose
-------------------------------------------------------------------------------------------------
Run
cd /d "%~dp0content"
git pull origin master
cd /d "%~dp0"
del /q /f "public\*.*"
for /d i"
mkdir public
copy /y ".flag" "public\.flag"
npm install
call npx quartz build --serve
-------------------------------------------------------------------------------------------------
@echo off
setlocal EnableDelayedExpansion
:menu
cls
echo ====================================
echo Git and Build Manager
echo ====================================
echo 1. Deploy (Git operations)
echo 2. Build (Quartz build)
echo 3. Run (Quartz serve)
echo 4. Exit
echo ====================================
set /p choice="Please enter your choice (1-4): "
if "%choice%"=="1" goto deploy
if "%choice%"=="2" goto build
if "%choice%"=="3" goto run
if "%choice%"=="4" goto end
goto menu
:deploy
echo.
echo Starting deployment process...
:: Navigate to the directory where the script is located
cd /d "%~dp0"
:: Stage all changes first
echo Staging all changes...
git add .
if !errorlevel! neq 0 (
echo Failed to stage changes.
pause
goto menu
)
:: Check if there are changes to commit
git diff --staged --quiet
if !errorlevel! equ 0 (
echo No changes to commit.
:: If no changes, update submodule and pull
echo Pulling latest changes from remote...
git pull origin master
echo Updating submodule...
git submodule update --remote --merge
pause
goto menu
)
:: Commit local changes first
set "timestamp=%date:~0,4date:~8,2%_%time:~0,2time:~6,2%"
set "timestamp=!timestamp: =0!"
echo Committing changes with timestamp: !timestamp!...
git commit -m "!timestamp!"
if !errorlevel! neq 0 (
echo Failed to commit changes.
pause
goto menu
)
:: Now pull remote changes
echo Pulling latest changes from remote...
git pull origin master
if !errorlevel! neq 0 (
echo Failed to pull changes.
pause
goto menu
)
:: Update submodule
echo Updating submodule...
git submodule update --remote --merge
if !errorlevel! neq 0 (
echo Failed to update submodule.
pause
goto menu
)
:: Push changes to the repository
echo Pushing changes to origin/master...
git push origin master
if !errorlevel! neq 0 (
echo Failed to push changes.
pause
goto menu
)
echo Changes successfully committed and pushed.
pause
goto menu
:build
echo.
echo Starting build process...
:: Step 1: Navigate to the 'content' directory
cd /d "%~dp0content"
:: Step 2: Update submodule by pulling the latest changes
echo Updating submodule...
git pull origin master
if !errorlevel! neq 0 (
echo Failed to update submodule.
pause
goto menu
)
:: Step 3: Return to the root directory
cd /d "%~dp0"
:: Step 4: Delete all contents in the 'public' folder
if exist "public" (
echo Deleting all contents in the 'public' folder...
del /q /f "public\*.*"
for /d i"
echo Deletion completed.
) else (
echo Creating public folder...
mkdir public
)
:: Step 5: Copy .flag file to public folder
echo Copying .flag file to public folder...
if exist ".flag" (
copy /y ".flag" "public\.flag"
echo .flag file copied successfully.
) else (
echo Warning: .flag file not found in root directory.
)
:: Step 6: Check if node_modules exists and install dependencies if needed
if not exist "node_modules" (
echo Installing dependencies...
npm install
if !errorlevel! neq 0 (
echo Failed to install dependencies.
pause
goto menu
)
)
:: Step 7: Build using Quartz
echo Building site with Quartz...
call npx quartz build --verbose
if !errorlevel! neq 0 (
echo Failed to build site. Error code: !errorlevel!
echo Please check if Quartz is properly installed and configured.
pause
goto menu
)
echo Build completed successfully.
pause
goto menu
:run
echo.
echo Starting server...
:: Step 1: Navigate to the 'content' directory
cd /d "%~dp0content"
:: Step 2: Update submodule by pulling the latest changes
echo Updating submodule...
git pull origin master
if !errorlevel! neq 0 (
echo Failed to update submodule.
pause
goto menu
)
:: Step 3: Return to the root directory
cd /d "%~dp0"
:: Step 4: Delete all contents in the 'public' folder
if exist "public" (
echo Deleting all contents in the 'public' folder...
del /q /f "public\*.*"
for /d i"
echo Deletion completed.
) else (
echo Creating public folder...
mkdir public
)
:: Step 5: Copy .flag file to public folder
echo Copying .flag file to public folder...
if exist ".flag" (
copy /y ".flag" "public\.flag"
echo .flag file copied successfully.
) else (
echo Warning: .flag file not found in root directory.
)
:: Step 6: Check if node_modules exists and install dependencies if needed
if not exist "node_modules" (
echo Installing dependencies...
npm install
if !errorlevel! neq 0 (
echo Failed to install dependencies.
pause
goto menu
)
)
:: Step 7: Run Quartz server
echo Starting Quartz server...
call npx quartz build --serve
if !errorlevel! neq 0 (
echo Failed to start server. Error code: !errorlevel!
echo Please check if Quartz is properly installed and configured.
pause
goto menu
)
echo Server stopped.
pause
goto menu
:end
echo Goodbye!
exit /b 0
06.nginx部署
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
# 开启访问日志,使用自定义格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'"$proxy_host" "$upstream_addr"'; # 添加代理信息
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
# 开启gzip压缩
gzip on;
# 设置gzip所需的http协议最低版本 (HTTP/1.1, HTTP/1.0)
gzip_http_version 1.1;
# 设置压缩级别,压缩级别越高压缩时间越长 (1-9)
gzip_comp_level 4;
# 设置压缩的最小字节数, 页面Content-Length获取
gzip_min_length 1000;
# 设置压缩文件的类型 (text/html)
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
server {
listen 83;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
# verify 页面路由 - 放在最前面处理
location = /verify {
root html/valut3;
try_files /verify.html =404;
}
# 静态网站配置
location / {
root html/valut3;
index index.html index.htm;
# 修改 try_files 配置,添加更严格的路径匹配
try_files $uri $uri.html $uri/index.html /index.html;
# 添加重写规则,防止路径重复
if ($request_uri ~* "^/(.*/)*([^/]+)/\2") {
rewrite ^/(.*) /$1 permanent;
}
}
# API 接口代理配置
location /api/auth {
# 转发到实际的验证服务器
proxy_pass http://localhost:3000/api/auth;
# proxy_pass https://valut-end.halavah.us/api/auth;
# 代理设置
proxy_set_header Host $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;
# Cookie 相关设置
proxy_cookie_path / /;
# 修改跨域配置 - 允许本地开发环境访问
set $cors_origin "";
if ($http_origin ~* "^(http://127\.0\.0\.1:83|http://localhost:83)$") {
set $cors_origin $http_origin;
}
add_header 'Access-Control-Allow-Origin' $cors_origin always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type' always;
# 处理 OPTIONS 预检请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' $cors_origin always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type' always;
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
}
# 静态资源缓存配置
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {
root html/valut3;
expires 30d;
add_header Cache-Control "public, no-transform";
# 添加重写规则,防止路径重复
if ($request_uri ~* "^/(.*/)*([^/]+)/\2") {
rewrite ^/(.*) /$1 permanent;
}
}
# 错误页面配置
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
07.caddy部署
a.方案1:caddy转发请求(放弃,得重写JS代码)
a.前端修改
// 使用相对路径
const getApiEndpoint = () => {
return '/api/auth'; // 让请求先到 Caddy
};
b.Caddy代理
handle /api/auth {
reverse_proxy https://valut-end.halavah.us
}
c.auth.ts验证
验证 Origin
处理 CORS
返回响应
b.方案2:caddy不转发请求(使用,20250311)
a.前端修改
// 使用相对路径
const getApiEndpoint = () => {
if (currentHost.includes('83')) {
// 直接访问验证服务器
return 'https://valut-end.halavah.us';
}
}
b.Caddy只代理静态请求
# verify 页面路由
handle /verify {
root * /etc/caddy/html/valut3
try_files /verify.html
file_server
}
# API 接口代理配置
# handle /api/auth {
# reverse_proxy https://valut-end.halavah.us {
# header_up Host {http.request.host}
# header_up X-Real-IP {remote_host}
# }
# }
c.auth.ts验证
验证 Origin
处理 CORS
返回响应
c.方案2:配置过程
a.quartz\util\verifyPage.ts => 生成到public\verify.html
const getApiEndpoint = () => {
const currentHost = window.location.host;
if (currentHost.includes('halavah')) {
return 'https://valut-end.halavah.us';
} else if (currentHost.includes('vercel')) {
return 'https://quartz-end.vercel.app';
} else if (currentHost.includes('83')) {
return 'https://valut-end.halavah.us'; // 配置该内容,会直接调用下面的axios请求
}
return 'http://localhost:3000';
};
form && form.addEventListener('submit', async (e) => {
e.preventDefault();
const password = passwordInput.value;
try {
const apiEndpoint = getApiEndpoint();
const response = await fetch(\`\${apiEndpoint}/api/auth?action=verify\`, { // axios请求
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ password }),
credentials: 'include',
});
const data = await response.json();
if (data.success) {
sessionStorage.setItem('v_p1', data.tokens.session);
sessionStorage.setItem('v_p2', data.tokens.local);
sessionStorage.setItem('v_p3', data.tokens.cookie);
const intendedPath = sessionStorage.getItem('intendedPath') || '/';
window.location.href = intendedPath;
} else {
throw new Error('Invalid password');
}
} catch (error) {
passwordInput.classList.add('error');
const errorMessage = document.createElement('div');
errorMessage.className = 'error-message';
errorMessage.textContent = 'Incorrect password. Please try again.';
form.appendChild(errorMessage);
errorMessage.style.display = 'block';
setTimeout(() => {
passwordInput.classList.remove('error');
errorMessage.style.display = 'none';
}, 3000);
}
});
b.quartz\components\pages\Content.tsx => 生成到public\prescript.js
const getApiEndpoint = () => {
const currentHost = window.location.host;
if (currentHost.includes('halavah')) {
return 'https://valut-end.halavah.us';
} else if (currentHost.includes('vercel')) {
return 'https://quartz-end.vercel.app';
} else if (currentHost.includes('83')) {
return 'https://valut-end.halavah.us'; // 配置该内容,会直接调用下面的axios请求
}
return 'http://localhost:3000';
};
const apiEndpoint = getApiEndpoint();
const response = await fetch(
\`\${apiEndpoint}/api/auth?action=check&session=\${encodeURIComponent(part1)}&local=\${encodeURIComponent(part2)}&cookie=\${encodeURIComponent(part3)}\`,
{
credentials: 'include',
}
);
c.Caddyfile
gz.pingx241030.me {
tls {
protocols tls1.2 tls1.3
curves x25519
alpn http/1.1 h2
}
reverse_proxy 100.64.0.4:82
}
# 将 :80 改为你的域名
kafuchino.online {
# 设置站点目录路径
root * /usr/share/caddy
# 启用静态文件服务器
file_server
# 如果需要,可以设置反向代理
# reverse_proxy localhost:8080
# 或者通过 php-fpm 提供 PHP 站点服务
# php_fastcgi localhost:9000
}
:80 {
# Set this path to your site's directory.
root * /usr/share/caddy
# Enable the static file server.
file_server
# Another common task is to set up a reverse proxy:
# reverse_proxy localhost:8080
# Or serve a PHP site through php-fpm:
# php_fastcgi localhost:9000
}
:82 {
reverse_proxy 100.64.0.8:82
}
:83 {
# 开启 Gzip 压缩
encode gzip {
minimum_length 1000
match {
header Content-Type text/*
header Content-Type application/json
header Content-Type application/javascript
header Content-Type application/xml*
}
}
# verify 页面路由
handle /verify {
root * /etc/caddy/html/valut3
try_files /verify.html
file_server
}
# API 接口代理配置
# handle /api/auth {
# reverse_proxy https://valut-end.halavah.us {
# header_up Host {http.request.host}
# header_up X-Real-IP {remote_host}
# }
# }
# 静态资源处理
handle {
# 静态资源缓存配置
@static_files path *.js *.css *.png *.jpg *.jpeg *.gif *.ico *.svg *.woff2
handle @static_files {
header Cache-Control "public, no-transform, max-age=2592000"
}
# 根目录配置
root * /etc/caddy/html/valut3
try_files {path} {path}.html {path}/index.html /index.html
file_server
}
# 错误页面配置
handle_errors {
root * html
rewrite * /50x.html
file_server
}
}
08.大纲+图谱
a.原
a.quartz.layout.ts,34行
export const defaultContentPageLayout: PageLayout = {
beforeBody: [
Component.Breadcrumbs(),
Component.ArticleTitle(),
Component.ContentMeta(),
Component.TagList(),
Component.MobileOnly(Component.TableOfContents()),
],
left: [
Component.PageTitle(),
Component.MobileOnly(Component.Spacer()),
Component.Search(),
Component.DesktopOnly(Component.Explorer()),
Component.DesktopOnly(Component.About()),
Component.MobileOnly(Component.Darkmode()),
],
right: [
Component.Graph(), --开启
Component.DesktopOnly(Component.TableOfContents()),
// Component.Backlinks(),
],
}
b.quartz/components/styles/toc.scss,8行
.toc {
display: flex;
flex-direction: column;
&.desktop-only {
max-height: 50%; --原本为50%
}
}
b.20250321
a.quartz.layout.ts,34行
export const defaultContentPageLayout: PageLayout = {
beforeBody: [
Component.Breadcrumbs(),
Component.ArticleTitle(),
Component.ContentMeta(),
Component.TagList(),
Component.MobileOnly(Component.TableOfContents()),
],
left: [
Component.PageTitle(),
Component.MobileOnly(Component.Spacer()),
Component.Search(),
Component.DesktopOnly(Component.Explorer()),
Component.DesktopOnly(Component.About()),
Component.MobileOnly(Component.Darkmode()),
],
right: [
// Component.Graph(), --关闭
Component.DesktopOnly(Component.TableOfContents()),
// Component.Backlinks(),
],
}
b.quartz/components/styles/toc.scss,8行
.toc {
display: flex;
flex-direction: column;
&.desktop-only {
max-height: 100%; --变为100%
}
}
5.7 textlint
01.安装(pangu.js)(autocorrect)
cnpm install textlint -g
02.规则包列表
cnpm install textlint-rule-ja-space-between-half-and-full-width -g
03.使用(默认情况下,只支持.txt和.md的自动检查和修复,其余后缀结尾的文件会被忽略)
a.将某个文件夹加入textlint管理
textlint --init
b.配置.textlintrc
{
"filters": {},
"rules": {
"ja-space-between-half-and-full-width": {
"space": "always"
}
}
}
c.命令
textlint . --对该目录及子目录下任意文本文件的格式检查
textlint demo.md --具体检查
textlint --fix demo.md --具体修复
textlint *.md --模糊检查
textlint --fix *.md --模糊修复
04.其他
a.只要文件通过文本形式储存,无论其后缀如何,均可以使用textlint进行检查
{
"filters": {},
"rules": {
"ja-space-between-half-and-full-width": {
"space": "always"
}
},
"plugins": {
"@textlint/markdown": {
"extensions": [".ipynb"]
}
}
}
b.白名单和过滤,可以将白名单词汇表allow.json文件添加到配置文件中
{
"filters": {
"whitelist": {
"whitelistConfigPaths": [
"./allow.json"
]
}
}
}
c.规则介绍
textlint-rule-no-dead-link:检查外部链接是否有效
textlint-rule-max-comma:用于检查一个长句子中限制的短句数量,如果逗号超过设定会进行提示
textlint-rule-max-number-of-lines:用于检查文档中的行数,如果超出了规定的行数即会进行提示
textlint-rule-no-exclamation-question-mark:强制修正问号和感叹号的使用
5.8 coding
01.登录
团队:https://halavah.coding.net/
邮箱:myslayers163.com
手机:15135890769
密码:XXXXXXXXX
腾讯云:100015247713
02.DevOps项目
DevOps项目(halavah) -> 持续部署 -> 名称blog、示例仓库、Hexo类型、北京 -> 部署
DevOps项目(halavah) -> 代码仓库(blog) -> 设置 -> 访问设置 -> 公开源代码
个人账号 -> 访问令牌 -> 令牌用户名(eTZrRAlbvz)、令牌(8d2ab38b92c68e06c9abb6253c77aa7945a60de4)
开源代码仓库 -> https://halavah.coding.net/public/
03.Gridea、Publii
平台 Coding Pages
域名 https://
仓库名称 halavah/blog
分支 master
仓库用户名 Halavah
邮箱 [email protected]
令牌用户名 eTZrRAlbvz
令牌 8d2ab38b92c68e06c9abb6253c77aa7945a60de4
CNAME halavah.buzz
04.Github搜索方式
in:name React stars:>5000 forks:>3000 language:python pushed:>2020-01-01
in:readme React stars:>5000 forks:>3000 language:python pushed:>2020-01-01
in:description React stars:>5000 forks:>3000 language:python pushed:>2020-01-01
5.9 vuepress
01.安装(vuepress 1.8.2)
yarn add global vuepress
02.配置
a.package.json
{
"name": "docs",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"docs:dev": "vuepress dev docs", --默认
"docs:build": "vuepress build docs" --默认
}
}
b./docs/README.md
# Introduction
## 项目介绍
练习项目:前后端不分离的博客
03.改造后
a.打开
cd D:\software_ware\workspace_picgo\vuepress
b.启动
git clone [email protected] :halavah/PicGo.git workspace_picgo --第1步:克隆仓库
git pull --rebase --第2步:更新仓库
vuepress dev vuepress --no-cache --第3步:查看本地,不会生成docs,支持预览
vuepress build vuepress --第4步:远程部署,生成docs,无法预览
git add . && git commit -m 'v1.0' && git push --第5步:手动提交
git tag v1.0 && git push origin v1.0 --第6步:手动提交
04.vercel
a.Framework Preset
VuePress
b.Root Directory
vuepress
c.BuildandOutputSettings
Build Command:vuepress build vuepress
Output Directory:../docs
Install Command:yarn add global vuepress
EnvironmentVariables:vuepress dev vuepress --port $PORT