摆弄服务器的记录¶
约 752 个字 245 行代码 4 张图片 预计阅读时间 6 分钟
用的是阿里云的99包年,继之前的qq机器人之后又零散整了一些活.
在服务器上配置vpn使用CodeX¶
阿里云的Linux发行版类型选择成Ubuntu, 然后在服务器的终端运行sudo apt install -y ubuntu-desktop来安装图形界面.
选择了FlClash-0.8.91-linux-amd64.AppImage 作为机场, 上传到服务器端的桌面.
在阿里云控制台使用VNC登录, 打开appimage即可. 关闭VNC的标签页并不会自动关闭图形界面, 所以可以使其一直运行.
当然, 此时并不意味着代理可以在VScode的ssh终端的CodeX CLI里或者VScode 的CodeX插件中使用, 因为ssh会话和VNC连接的图形界面是不同的会话. Linux的对终端间的隔离包括登录会话作用域和进程树作用域, 比如不同用户的~/.bash_profile / ~/.bash_login / `~/.profile是分开的, 不同用户创建的会话会注入不同的环境, 而进程树作用域是指某个终端的环境变量只对该终端的子进程有效. 所以此时只在图形界面终端可以使用VPN, 因为FlClash本质是设置了环境变量为127.0.0.1:7890.
另外一个问题是, 如果直接在VScode的ssh打开FlClash的app image, 会显示因为缺失显示器从而无法启动:
root@iZbp18go8yddw5y53guhdbZ:/home/yuqizhang/Desktop# ./FlClash-0.8.91-linux-amd64.AppImage
(com.follow.clash:54774): Gtk-WARNING **: 17:00:15.792: cannot open display:
DISPLAY, 可以通过将图形界面的DISPLAY设置为ssh终端的DISPLAY来解决. 在VNC连接的图形界面打开终端, 通过echo $DISPLAY查看到VNC的图形界面为:0, 因此在ssh终端中也应设置$DISPLAY = :0. 此时若直接访问会显示Authorization required, 这与xhost的配置有关. xhost是为X Window系统中控制x服务器访问权限的工具, x服务器是负责Linux系统的GUI绘制渲染和处理GUI输入事件的程序. 因为ssh终端的root用户无权访问图形界面(user用户登录), 所以无法打开. 此时在图形界面的终端中输入xhost +si:localuser:root向用户root授予权限即可.
因此, 在我ssh登录的root用户的~/.bashrc中添加了如下逻辑, 是的在每次启动root用户的ssh连接时
-
设置环境变量
DISPLAY=":0" -
使用
ps -a检查FlClash进程是否存在, 若不存在则运行/home/yuqizhang/Desktop/FlClash-0.8.91-linux-amd64.AppImage -
如果FlClash启动成功或者已经在运行, 输出“ FlClash SSH bootstrap: FlClash is already running.”, 再进行PROXY环境变量设置,而后输出”PROXY setup success”+ 各代理环境变量的代理地址:
-
若FlClash启动失败, 输出”FlClash SSH bootstrap: FlClash lauch fail.”并输出”PROXY setup fail.”
bash脚本如下:
# ===== FlClash + proxy bootstrap for SSH interactive shells =====
# Only run in interactive shells
case "$-" in
*i*) ;;
*) return ;;
esac
# Only run for SSH sessions
if [ -z "${SSH_CONNECTION:-}" ] && [ -z "${SSH_TTY:-}" ]; then
return
fi
# 1) DISPLAY (assumes local GUI session is :0)
export DISPLAY="${DISPLAY:-:0}"
FLCLASH_APPIMAGE="/home/yuqizhang/Desktop/FlClash-0.8.91-linux-amd64.AppImage"
FLCLASH_LOG="/var/log/flclash-ssh-autostart.log"
FLCLASH_LOCK="/tmp/flclash-autostart.lock"
# Helper: check whether FlClash is running
_flclash_is_running() {
pgrep -x "FlClash" >/dev/null 2>&1 && return 0
pgrep -f "FlClashCore" >/dev/null 2>&1 && return 0
return 1
}
# Helper: attempt to launch FlClash (detached)
_flclash_launch() {
[ -x "$FLCLASH_APPIMAGE" ] || return 1
( nohup "$FLCLASH_APPIMAGE" >>"$FLCLASH_LOG" 2>&1 & ) >/dev/null 2>&1
return 0
}
# Ensure FlClash is running; return 0 on success, 1 on failure
_ensure_flclash() {
# Fast path
_flclash_is_running && return 0
# If flock exists, prevent concurrent multiple starts
if command -v flock >/dev/null 2>&1; then
exec 9>"$FLCLASH_LOCK" || true
if flock -n 9; then
# We hold the lock; try launching
_flclash_launch || true
# Wait briefly for the process to appear (non-blocking, short)
for _i in 1 2 3 4 5; do
_flclash_is_running && break
sleep 0.3
done
flock -u 9 || true
else
# Another session may be starting it; wait a moment and recheck
for _i in 1 2 3 4 5; do
_flclash_is_running && break
sleep 0.3
done
fi
exec 9>&- || true
else
# No flock: best-effort start with a small wait
_flclash_launch || true
for _i in 1 2 3 4 5; do
_flclash_is_running && break
sleep 0.3
done
fi
_flclash_is_running && return 0
return 1
}
# Main logic
if _ensure_flclash; then
echo " FlClash SSH bootstrap: FlClash is already running."
# 3) Proxy env vars (only set on success)
export HTTP_PROXY="http://127.0.0.1:7890"
export HTTPS_PROXY="$HTTP_PROXY"
export ALL_PROXY="socks5h://127.0.0.1:7890"
export NO_PROXY="localhost,127.0.0.1"
echo "PROXY setup success"
echo "HTTP_PROXY=$HTTP_PROXY"
echo "HTTPS_PROXY=$HTTPS_PROXY"
echo "ALL_PROXY=$ALL_PROXY"
echo "NO_PROXY=$NO_PROXY"
else
echo " FlClash SSH bootstrap: FlClash lauch fail."
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY
echo "PROXY setup fail."
fi
# ===== end bootstrap =====
在进行了如上设置后, 为了使CodeX的VSCode插件(安装在服务器端)能够顺畅使用, 还要在VScode中配置http.proxy(在服务器端)
效果如下:

阿里云服务器+腾讯云邮件推送服务搭建邮件服务器¶
在阿里云ECS上, TCP 25端口的出方向是默认被封的, 所以不能直接使用阿里云做ECS服务器.
而腾讯云的邮件推送服务有每个账号1000封邮件的免费发送额度, 超出免费额度的部分为按量日结(0.0019元/封), 所以直接在阿里云服务器里登录腾讯云服务器. 用GPT参照腾讯云的官方文档写了个python脚本:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# export TC_SMTP_PASS="smtp_ZYQ753421"
# python3 send_tencent_smtp.py \
# --region hk \
# --port 465 \
# --to "1826358454@qq.com" \
# --subject "Hello via Tencent SMTP relay" \
# --text "This is a test email." \
# --debug
import argparse
import os
import ssl
import smtplib
import time
from email.message import EmailMessage
from email.utils import formataddr, make_msgid
REGION_HOST = {
"hk": "smtp.qcloudmail.com",
"gz": "gz-smtp.qcloudmail.com",
"sg": "sg-smtp.qcloudmail.com",
}
DEFAULT_FROM = "[邮件域名]"
def build_message(from_email, from_name, to_emails, subject, text_body, html_body=None):
msg = EmailMessage()
msg["Subject"] = subject
msg["From"] = formataddr((from_name, from_email))
msg["To"] = ", ".join(to_emails)
msg["Message-ID"] = make_msgid()
if html_body:
msg.set_content(text_body or "This message contains HTML content.")
msg.add_alternative(html_body, subtype="html")
else:
msg.set_content(text_body or "")
return msg
def _smtp_send_ssl(host, port, username, password, msg, timeout, debug, context):
server = smtplib.SMTP_SSL(host=host, port=port, context=context, timeout=timeout)
try:
if debug:
server.set_debuglevel(1)
server.ehlo()
server.login(username, password)
server.send_message(msg)
finally:
try:
server.quit()
except Exception:
pass
def _smtp_send_starttls(host, port, username, password, msg, timeout, debug, context):
server = smtplib.SMTP(host=host, port=port, timeout=timeout)
try:
if debug:
server.set_debuglevel(1)
server.ehlo()
server.starttls(context=context)
server.ehlo()
server.login(username, password)
server.send_message(msg)
finally:
try:
server.quit()
except Exception:
pass
def send_via_tencent_smtp(host, port, username, password, msg, timeout=120, debug=False, starttls=False):
"""
- 默认:465/587 走 SMTP_SSL(隐式 TLS)
- 如指定 --starttls:走 STARTTLS(常用于 587/25)
同时做一次“禁用 TLS1.3 / 强制 TLS1.2+ciphers”的重试,以兼容部分服务端。
"""
# Attempt 1: default context, and (optionally) disable TLSv1.3
ctx1 = ssl.create_default_context()
if hasattr(ssl, "OP_NO_TLSv1_3"):
ctx1.minimum_version = ssl.TLSVersion.TLSv1_2
try:
if starttls:
_smtp_send_starttls(host, port, username, password, msg, timeout, debug, ctx1)
else:
_smtp_send_ssl(host, port, username, password, msg, timeout, debug, ctx1)
return
except (TimeoutError, smtplib.SMTPServerDisconnected, ssl.SSLError) as e:
if debug:
print(f"[warn] First attempt failed: {repr(e)}; retry with TLSv1.2 + conservative ciphers...")
time.sleep(2)
# Attempt 2: force TLSv1.2 + conservative ciphers
ctx2 = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
ctx2.set_ciphers("AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5")
if starttls:
_smtp_send_starttls(host, port, username, password, msg, timeout, debug, ctx2)
else:
_smtp_send_ssl(host, port, username, password, msg, timeout, debug, ctx2)
def main():
p = argparse.ArgumentParser(description="Send email via Tencent Cloud Email Delivery SMTP relay.")
p.add_argument("--region", choices=REGION_HOST.keys(), default="gz")
p.add_argument("--host", default=None, help="Override SMTP host (optional)")
p.add_argument("--port", type=int, default=465, help="465/587/25")
p.add_argument("--starttls", action="store_true", help="Use STARTTLS instead of implicit TLS (SMTP_SSL).")
p.add_argument("--from-email", default=os.getenv("TC_SMTP_USER", DEFAULT_FROM))
p.add_argument("--from-name", default=os.getenv("TC_FROM_NAME", "[发件人姓名]"))
p.add_argument("--password", default=os.getenv("TC_SMTP_PASS", "[腾讯云SMTP密码]"))
p.add_argument("--to", action="append", required=True, help="Recipient email (repeatable)")
p.add_argument("--subject", default="Hello via Tencent SMTP relay")
p.add_argument("--text", default="This is a test email.")
p.add_argument("--html", default=None)
p.add_argument("--timeout", type=int, default=120)
p.add_argument("--debug", action="store_true")
args = p.parse_args()
host = args.host or REGION_HOST[args.region]
if not args.password:
raise SystemExit("Missing SMTP password. Use --password or env TC_SMTP_PASS.")
msg = build_message(
from_email=args.from_email.strip(),
from_name=args.from_name,
to_emails=[t.strip() for t in args.to],
subject=args.subject,
text_body=args.text,
html_body=args.html,
)
send_via_tencent_smtp(
host=host,
port=args.port,
username=args.from_email.strip(), # Tencent SMTP: username 通常就是发信地址
password=args.password,
msg=msg,
timeout=args.timeout,
debug=args.debug,
starttls=args.starttls,
)
print(f"OK: sent via {host}:{args.port} (starttls={args.starttls}) to {args.to}")
if __name__ == "__main__":
main()