有的命令一个月可能就用那么几次,不写手册里谁能记得住啊
VSCode
解决 code-runner Java Output 乱码
"code-runner.executorMap": {
"javascript": "node",
"java": "\"C:/Program Files/Java/jdk-17/bin/java.exe\" -Dfile.encoding=UTF-8",
PowerShell
快速完成端口转发
netsh interface portproxy add v4tov4 `
listenaddress=0.0.0.0 `
listenport=2375 `
connectaddress=127.0.0.1 `
connectport=2375
查端口占用 杀进程
netstat -aon | findstr :8080
taskkill /PID 39656 /F
自定义常用命令别名
notepad $PROFILE
function gacp {
param (
[string]$msg = "update"
)
git add .
git commit -m $msg
git push
}
# 删除当前文件夹下空文件夹
function rme {
Get-ChildItem -Directory -Recurse | Where-Object { $_.GetFileSystemInfos().Count -eq 0 } | Remove-Item
}
Linux
Linux开辟虚拟内存(Swap)
free -h
Linux实现FRP内网穿透
的是让国内用户能连到一台没有公网 IP 的家庭电脑——用的是反向内网穿透:
国内用户 → 云服务器(有公网IP,域名解析到它)→ frps(服务端,监听公网端口)
↕ frpc主动拨出的加密隧道
家里PopOS笔记本 → frpc(客户端)→ 本地80/443服务
角色分工:frps 装在云服务器(被动等连接的一方,因为它有公网 IP);frpc 装在家里笔记本(主动连出去的一方,因为它在 NAT 后面没有公网 IP)。
frps 端配置(云服务器)
/root/frp_0.61.0_linux_amd64/frps.toml:
bindPort = 7000 # 控制端口,frpc就是连这个端口上来注册
auth.method = "token"
auth.token = "2b65b0b89f8ff57fcb1a631176605898" # frpc必须带同样的token才能连上
log.to = "/var/log/frps.log"
log.level = "info"
log.maxDays = 7
systemd 服务 /etc/systemd/system/frps.service:
[Unit]
Description=frp server
After=network.target
[Service]
Type=simple
User=root
Restart=on-failure
RestartSec=5s
ExecStart=/root/frp_0.61.0_linux_amd64/frps -c /root/frp_0.61.0_linux_amd64/frps.toml
[Install]
WantedBy=multi-user.target
systemctl enable --now frps 之后开机自启、崩溃自动重启。
frpc 端配置(家里笔记本)
/etc/frp/frpc.toml:
serverAddr = "yjsws.cn" # 域名已解析到云服务器,直接用域名
serverPort = 7000 # 对应frps的bindPort
auth.method = "token"
auth.token = "2b65b0b89f8ff57fcb1a631176605898" # 必须和frps一致
[[proxies]]
name = "home-http"
type = "tcp"
localIP = "127.0.0.1"
localPort = 80 # 笔记本本地网站监听的端口
remotePort = 80 # 云服务器上对外暴露的端口
[[proxies]]
name = "home-https"
type = "tcp"
localIP = "127.0.0.1"
localPort = 443
remotePort = 443
对应 systemd 服务 /etc/systemd/system/frpc.service:
[Unit]
Description=frp client
After=network.target
[Service]
Type=simple
Restart=on-failure
RestartSec=5s
ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.toml
[Install]
WantedBy=multi-user.target
几个关键决策
1. 选了 type = "tcp" 纯透传,没用 type = "http"/"https" 的 vhost 模式
好处是简单直接、字节原样转发,适合单域名测试;代价是 frps 完全不解密流量,TLS 握手是浏览器和笔记本之间直接做的——这也是为什么证书必须装在笔记本上,而不能复用云服务器那张(TLS 到底在哪一端终止,证书就必须在哪一端)。
如果以后要在同一个 frps 上挂多个域名/多个后端,才需要换成 vhost 模式:
vhostHTTPPort = 80
vhostHTTPSPort = 443
配合 proxy 里的 customDomains = ["a.com"] 做基于域名的分流,此时 frps 可以在 HTTP 层面按域名转发给不同的后端。
2. 云服务器的 80/443 端口冲突
之前 nginx 占着这两个端口给 yjsws.cn 提供服务,得先 systemctl stop nginx && systemctl disable nginx 腾出端口给 frps 直接监听。
副作用:nginx 自己的 certbot 续期机制也跟着失效了——续期要用 80 端口做 HTTP-01 验证,但 80 现在整个转发给了笔记本,云服务器本地已经没有东西能应答验证请求了。所以证书管理这件事顺势也挪到了笔记本那边(用笔记本上的 nginx + certbot 重新申请,续期时验证请求会通过隧道打到笔记本本地完成)。
3. 安全性
auth.token是 frpc 能连上 frps 的唯一门槛,泄露了等于任何人都能借用这条隧道把流量转到别处,得当密码保管。- 阿里云的安全组是控制台层面的东西,和本机
iptables是两码事——本机防火墙放行不代表外部真能连进来,得单独去控制台确认80/443/7000入方向规则开了。 7000控制端口测试期间是开着的,长期使用建议加白名单限制来源 IP,或者收紧到仅允许家里笔记本的出口 IP。
验证方式
tail -f /var/log/frps.log # 看frpc有没有成功login、代理有没有注册成功("new proxy [home-http] ... success")
ss -tulnp | grep -E ':80 |:443 ' # 确认frps确实在监听这两个端口(frpc连上来注册后才会动态绑定,不是一启动就有)
curl -o /dev/null -w '%{http_code}' http://yjsws.cn/ # 端到端实测,能拿到笔记本网站的真实响应
其他
# 1Panel
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh
# zsh
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
# 服务器测试
curl -sL yabs.sh | bash
# 备份
ssh root@你的VPS_IP \
"dd if=/dev/vda bs=4M status=progress | gzip" \
> vps.img.gz
Git
Windows 一键生成 .gitignore
function shell {
param(
[Parameter(Mandatory=$true)]
[string]$Arguments
)
$targets = $Arguments -replace ' ', ','
$url = "https://www.toptal.com/developers/gitignore/api/$targets"
Invoke-WebRequest -Uri $url -OutFile .gitignore
Write-Host "[SUCCESS] .gitignore generated for: [$Arguments]" -ForegroundColor Green
}
反向代理(Nginx)
Nginx 一键部署(Linux)
#!/bin/bash
# ================================================
# Nginx 一键安装脚本
# 支持: Ubuntu/Debian / CentOS/RHEL/Rocky/Alma
# 作者: LOCRIAN_V
# ================================================
set -e
# -------- 颜色输出 --------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
info() { echo -e "${CYAN}[INFO]${NC} $1"; }
success() { echo -e "${GREEN}[OK]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERR]${NC} $1"; exit 1; }
# -------- 检查 root --------
if [[ $EUID -ne 0 ]]; then
error "请使用 root 或 sudo 运行此脚本"
fi
# -------- 检测发行版 --------
detect_os() {
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$ID
OS_VERSION=$VERSION_ID
else
error "无法识别操作系统,请手动安装 Nginx"
fi
}
# -------- 安装函数 --------
install_nginx_debian() {
info "检测到 Debian/Ubuntu 系统 (${OS} ${OS_VERSION})"
info "更新软件包列表..."
apt-get update -y
info "安装依赖..."
apt-get install -y curl gnupg2 ca-certificates lsb-release debian-archive-keyring
info "添加 Nginx 官方仓库..."
curl -fsSL https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
-o /usr/share/keyrings/nginx-archive-keyring.gpg
# 根据发行版选择仓库
if [[ "$OS" == "ubuntu" ]]; then
CODENAME=$(lsb_release -cs)
REPO_TYPE="ubuntu"
else
CODENAME=$(lsb_release -cs)
REPO_TYPE="debian"
fi
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
https://nginx.org/packages/${REPO_TYPE} ${CODENAME} nginx" \
> /etc/apt/sources.list.d/nginx.list
# 仓库优先级
echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900" \
> /etc/apt/preferences.d/99nginx
apt-get update -y
apt-get install -y nginx
}
install_nginx_rhel() {
info "检测到 RHEL/CentOS/Rocky/Alma 系统 (${OS} ${OS_VERSION})"
MAJOR_VER=$(echo "$OS_VERSION" | cut -d. -f1)
info "添加 Nginx 官方仓库..."
cat > /etc/yum.repos.d/nginx.repo <<EOF
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/${MAJOR_VER}/\$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
EOF
info "安装 Nginx..."
if command -v dnf &>/dev/null; then
dnf install -y nginx
else
yum install -y nginx
fi
}
# -------- 配置防火墙 --------
configure_firewall() {
info "配置防火墙放行 80/443..."
if command -v ufw &>/dev/null; then
ufw allow 'Nginx Full' 2>/dev/null || ufw allow 80/tcp && ufw allow 443/tcp
success "UFW 已放行 80/443"
elif command -v firewall-cmd &>/dev/null; then
firewall-cmd --permanent --add-service=http 2>/dev/null || true
firewall-cmd --permanent --add-service=https 2>/dev/null || true
firewall-cmd --reload 2>/dev/null || true
success "firewalld 已放行 80/443"
else
warn "未检测到 ufw/firewalld,请手动放行 80/443 端口"
fi
}
# -------- 启动并设置开机自启 --------
enable_nginx() {
info "启动 Nginx 并设置开机自启..."
systemctl enable nginx
systemctl start nginx
success "Nginx 已启动"
}
# -------- 打印结果 --------
print_result() {
NGINX_VERSION=$(nginx -v 2>&1 | awk -F'/' '{print $2}')
IP=$(hostname -I | awk '{print $1}')
echo ""
echo -e "${GREEN}================================================${NC}"
echo -e "${GREEN} Nginx 安装成功!${NC}"
echo -e "${GREEN}================================================${NC}"
echo -e " 版本: ${CYAN}${NGINX_VERSION}${NC}"
echo -e " 访问地址: ${CYAN}http://${IP}${NC}"
echo -e " 配置文件: ${CYAN}/etc/nginx/nginx.conf${NC}"
echo -e " 站点目录: ${CYAN}/etc/nginx/conf.d/${NC}"
echo -e " 默认网站根: ${CYAN}/usr/share/nginx/html${NC}"
echo -e " 日志目录: ${CYAN}/var/log/nginx/${NC}"
echo ""
echo -e " 常用命令:"
echo -e " ${YELLOW}systemctl start|stop|restart|status nginx${NC}"
echo -e " ${YELLOW}nginx -t${NC} # 检查配置语法"
echo -e " ${YELLOW}nginx -s reload${NC} # 热重载配置"
echo -e "${GREEN}================================================${NC}"
}
# -------- 主流程 --------
main() {
echo ""
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN} Nginx 一键安装脚本 by LOCRIAN_V ${NC}"
echo -e "${CYAN}========================================${NC}"
echo ""
detect_os
# 检查是否已安装
if command -v nginx &>/dev/null; then
warn "Nginx 已安装: $(nginx -v 2>&1)"
read -p "是否重新安装?(y/N): " REINSTALL
[[ "$REINSTALL" =~ ^[Yy]$ ]] || { info "跳过安装"; print_result; exit 0; }
fi
case "$OS" in
ubuntu|debian)
install_nginx_debian
;;
centos|rhel|rocky|almalinux|ol)
install_nginx_rhel
;;
*)
error "不支持的发行版: $OS,支持 Ubuntu/Debian/CentOS/RHEL/Rocky/Alma"
;;
esac
configure_firewall
enable_nginx
print_result
}
main "$@"
容器化与运维 (Docker)
Docker 安装 (Linux)
# 下载官方安装脚本
curl -fsSL https://get.docker.com -o get-docker.sh
# 运行脚本安装 Docker
sudo sh ./get-docker.sh
Docker 备份恢复卷
# 备份
docker run --rm -v 卷名:/source -v $(pwd):/backup alpine tar czf /backup/备份文件名.tar.gz -C /source .
# 恢复
# 如果 Volume 已存在,直接恢复(会覆盖原有数据)
docker run --rm -v existing-volume:/restore -v $(pwd):/backup alpine tar xzf /backup/auth-backup-20240115.tar.gz -C /restore
微服务 dockercompose
FROM eclipse-temurin:17-jre
# 哪个服务由 compose 的 build.args 传进来
ARG MODULE
ENV TZ=Asia/Shanghai
WORKDIR /app
COPY ${MODULE}/target/${MODULE}-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
services:
# ===== 基础设施 =====
nacos:
image: nacos/nacos-server:v2.4.3
container_name: nacos
restart: always
environment:
MODE: standalone
# 4G 预算下进一步收窄,standalone 模式够用
JVM_XMS: 512m
JVM_XMX: 768m
JVM_XMN: 256m
ports:
- "8848:8848"
- "9848:9848"
networks:
- backend_network
deploy:
resources:
limits:
memory: 2g # ≈ JVM_XMX(256m) × 1.25,standalone 元数据量小,余量可以收紧
cpus: "0.5"
mysql:
image: mysql:8.0.36
container_name: mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
TZ: Asia/Shanghai
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./docker/mysql/mysql-init:/docker-entrypoint-initdb.d
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}" ]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
networks:
- backend_network
redis:
image: redis:7-alpine
container_name: redis
restart: always
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD}
# 4G 预算下 maxmemory 收到 128mb,chat-service 的 Pub/Sub 消息体本身很小,够用
command: redis-server --maxmemory 128mb --maxmemory-policy allkeys-lru
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
interval: 10s
timeout: 5s
retries: 5
networks:
- backend_network
deploy:
resources:
limits:
memory: 192m # ≈ maxmemory(128mb) + 持久化/连接开销余量
cpus: "0.3"
kafka:
image: apache/kafka:3.9.0
container_name: kafka
hostname: kafka
ports:
- "9092:9092"
environment:
# 单节点 KRaft,本地开发吞吐量低,堆没必要给到 512m
KAFKA_HEAP_OPTS: "-Xms192m -Xmx256m"
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: broker,controller
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
KAFKA_LISTENERS: PLAINTEXT://:9092,INTERNAL://:29092,CONTROLLER://:9093
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092,INTERNAL://kafka:29092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,INTERNAL:PLAINTEXT,CONTROLLER:PLAINTEXT
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
# 单分区场景下页缓存/日志段没必要预留太多,缩小段大小减少常驻内存
KAFKA_LOG_SEGMENT_BYTES: 268435456
CLUSTER_ID: MkU3OEVBNTcwNTJENDM2Qk
restart: unless-stopped
volumes:
- kafka_data:/var/lib/kafka/data
networks:
- backend_network
# Kafka GUI,纯调试工具,日常不需要常驻,用 profile 隔离,需要看 topic 时再启:
# docker compose --profile debug up -d kafdrop
kafdrop:
image: obsidiandynamics/kafdrop
container_name: kafdrop
profiles: ["debug"]
ports:
- "9000:9000"
environment:
KAFKA_BROKERCONNECT: "kafka:29092"
SERVER_SERVLET_CONTEXTPATH: "/"
restart: unless-stopped
networks:
- backend_network
deploy:
resources:
limits:
memory: 160m
cpus: "0.3"
# ===== 业务微服务 =====
# 统一约定:JAVA_OPTS 需要 Dockerfile 的 ENTRYPOINT 用 `sh -c "java $JAVA_OPTS -jar app.jar"`
# 这种形式读取环境变量才会生效,如果是写死的 `java -jar app.jar` 需要先改 Dockerfile。
# -XX:+UseSerialGC + -XX:ActiveProcessorCount=1:容器只分到 <1 核时,G1 的多 GC 线程反而是负担
# -XX:+ExitOnOutOfMemoryError:内存不够时让容器直接重启,而不是卡死在一个不可用状态
gateway:
restart: unless-stopped
networks:
- backend_network
volumes:
- ./.env:/app/.env:ro
environment:
JAVA_OPTS: >-
-Xms256m -Xmx512m
depends_on:
mysql: { condition: service_healthy }
redis: { condition: service_healthy }
container_name: gateway
build: { context: ., args: { MODULE: gateway } }
env_file:
- .env
ports:
- "8080:8080"
auth-service:
restart: unless-stopped
networks:
- backend_network
volumes:
- ./.env:/app/.env:ro
environment:
JAVA_OPTS: >-
-Xms256m -Xmx512m
depends_on:
mysql: { condition: service_healthy }
redis: { condition: service_healthy }
env_file:
- .env
container_name: auth-service
build: { context: ., args: { MODULE: auth-service } }
user-service:
restart: unless-stopped
networks:
- backend_network
volumes:
- ./.env:/app/.env:ro
environment:
JAVA_OPTS: >-
-Xms256m -Xmx512m
depends_on:
mysql: { condition: service_healthy }
redis: { condition: service_healthy }
env_file:
- .env
container_name: user-service
build: { context: ., args: { MODULE: user-service } }
family-service:
restart: unless-stopped
networks:
- backend_network
volumes:
- ./.env:/app/.env:ro
environment:
JAVA_OPTS: >-
-Xms256m -Xmx512m
depends_on:
mysql: { condition: service_healthy }
redis: { condition: service_healthy }
env_file:
- .env
container_name: family-service
build: { context: ., args: { MODULE: family-service } }
chat-service:
restart: unless-stopped
networks:
- backend_network
volumes:
- ./.env:/app/.env:ro
environment:
JAVA_OPTS: >-
-Xms256m -Xmx512m
depends_on:
mysql: { condition: service_healthy }
redis: { condition: service_healthy }
env_file:
- .env
container_name: chat-service
build: { context: ., args: { MODULE: chat-service } }
location-service:
restart: unless-stopped
networks:
- backend_network
volumes:
- ./.env:/app/.env:ro
environment:
JAVA_OPTS: >-
-Xms256m -Xmx512m
depends_on:
mysql: { condition: service_healthy }
redis: { condition: service_healthy }
env_file:
- .env
container_name: location-service
build: { context: ., args: { MODULE: location-service } }
moment-service:
restart: unless-stopped
networks:
- backend_network
volumes:
- ./.env:/app/.env:ro
environment:
JAVA_OPTS: >-
-Xms256m -Xmx512m
depends_on:
mysql: { condition: service_healthy }
redis: { condition: service_healthy }
env_file:
- .env
container_name: moment-service
build: { context: ., args: { MODULE: moment-service } }
health-service:
restart: unless-stopped
networks:
- backend_network
volumes:
- ./.env:/app/.env:ro
environment:
JAVA_OPTS: >-
-Xms256m -Xmx512m
depends_on:
mysql: { condition: service_healthy }
redis: { condition: service_healthy }
env_file:
- .env
container_name: health-service
build: { context: ., args: { MODULE: health-service } }
redpacket-service:
restart: unless-stopped
networks:
- backend_network
volumes:
- ./.env:/app/.env:ro
environment:
JAVA_OPTS: >-
-Xms256m -Xmx512m
depends_on:
mysql: { condition: service_healthy }
redis: { condition: service_healthy }
env_file:
- .env
container_name: redpacket-service
build: { context: ., args: { MODULE: redpacket-service } }
volumes:
mysql_data:
redis_data:
kafka_data:
networks:
backend_network:
driver: bridge
快捷命令
# 一键停止所有容器
docker stop $(docker ps -q)
MySQL
- 持久化数据卷创建:
docker volume create mysql-data
- 常用启动参数提示:
-d(后台运行容器)
n8n (自动化工作流引擎)
- 持久化数据卷创建:
docker volume create n8n_data
- 容器启动命令:
docker run -it --rm \
--name n8n \
-p 5678:5678 \
-e GENERIC_TIMEZONE="Asia/Shanghai" \
-e TZ="Asia/Shanghai" \
-e N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true \
-e N8N_RUNNERS_ENABLED=true \
-v n8n_data:/home/node/.n8n \
docker.n8n.io/n8nio/n8n
💡 提示: 生产环境建议将
-it --rm(交互式运行且退出后删除)替换为-d --restart always以保障后台常驻运行。
开发环境与语言 (Development Environment)
Node.js (Linux 环境安装)
推荐使用 NVM (Node Version Manager) 进行版本管理,安装与验证步骤如下:
# 1. 下载并安装 nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash
# 2. 刷新环境变量 (免重启 Shell)
\. "$HOME/.nvm/nvm.sh"
# 3. 安装指定版本的 Node.js (以 v24 为例)
nvm install 24
# 4. 验证安装结果
node -v # 应输出 "v24.x.x"
npm -v # 应输出对应的 npm 版本
其它常用命令 (Miscellaneous)
export:用于在 Linux 中设置或导出环境变量。
神秘代码
Linux
wget -P /root -N --no-check-certificate "https://raw.githubusercontent.com/mack-a/v2ray-agent/master/install.sh" && chmod +x install.sh && ./install.sh
Windows
irm https://get.activated.win | iex
irm https://christitus.com/win | iex
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser; iex (irm get.scoop.sh)
winget install JanDeDobbeleer.OhMyPosh -s winget
oh-my-posh init pwsh | Invoke-Expression
oh-my-posh font install
# 展示配置
winget install Fastfetch