一个基于 GitHub Actions 和 requests 库的自动化脚本,用于自动续约 EUserv 提供的免费 VPS 计划。脚本通过精确模拟浏览器请求和邮件交互,实现无人值守的自动化续约。
- 🔴 修复验证码丢失:修复首次登录触发验证码时
sess_id未及时同步引起的验证码提交失败 - 🔴 增强邮件重试网络恢复:IMAP 连接断开或认证异常将触发条件重试,遇到网络波动不再直接崩毁
- 🔴 修复状态邮件误报:使用智能调度跳过续约时(未到期),邮件报告明确标记为“跳过”而非误报“成功”
- 🟡 修复续期状态覆写:增加
_safe_refresh_session(),避免续期成功后附带的刷新 session 失败覆写主干成功状态
- 🛡️ 统一请求源头:统一所有请求
Origin头为https://support.euserv.com,防范风控拦截 - 🔧 构建完善:添加
pyproject.toml规范环境与 pytest pythonpath (移除sys.pathhack),清理无效冗余返回值和注释
- 🔴 Session 过期自动重连:新增
_refresh_session()方法,续期流程耗时较长后自动重新登录,防止_check_post_renewal_status因 session 过期而失败 - 📧 邮件编码兼容:
_extract_email_body()使用part.get_content_charset()获取真实编码,支持多种邮件编码格式,避免 UTF-8 硬编码导致的解码失败
- 🔧 简化
_handle_captcha参数(7→3),直接从实例读取凭据 - 🔧 简化
_handle_2fa参数(3→1),内联 origin header 保持原始https://www.euserv.com - 🔧
_renew返回值从bool改为None(始终返回 True 无意义) - 🔧 提取
SERVER_LIST_RETRY_DELAY常量,替代sleep(30)硬编码 - 🗑️ 移除多余的
http://重试适配器(Euserv 纯 HTTPS)
- ✅ 修正测试名
test_parentheses_not_supported→test_parentheses_work - 🧹 移除
test_safe_eval.py中未使用的pytestimport
- ⚡ 启用 Node.js 24,消除 GitHub Actions 弃用警告
v2.2.0 及更早版本
- 🔴 修复 cron 调度不更新:空服务器列表不再静默成功,改为
EXIT_FAILURE并保存调试页面 - 🔴 修复续约后 cron 丢失:无论续约状态如何均输出下次续约日期
- 🔴 修复测试套件:修复因函数重命名导致的 ImportError(3 个测试文件)
- 🔒 2FA 密码和 PIN 码日志遮蔽,仅显示末 2 位
- 🛡️ 新增
HTTPAdapter+Retry自动重试策略(5xx 状态码) - 🌐 User-Agent 更新至 Chrome 131
- 🎯 使用
ddddocr.set_ranges()限制字符集,提高数学验证码识别率 - 🧹 提取
_clean_math_expr()/_try_solve_math()统一数学表达式处理 - 🧹 提取
_parse_server_row()降低认知复杂度 - 📊 服务器列表解析增加行数日志,空结果保存 HTML 用于调试
- 🏗️ Phase 3 架构统一:将 15+ 顶层函数移入
RenewalBot类 - 🧹 消除全局变量
LOG_MESSAGES,CURRENT_LOGIN_ATTEMPT,_ocr_instance - ⚡ OCR 预热:启动时预加载模型,减少首次识别延迟
- 🔒 HTTP Session 资源管理:添加
_cleanup()方法确保正确关闭
- 🧪 新增 pytest 测试套件 (
tests/test_renewal.py) - 🎯 9 个测试类覆盖核心功能
- 📝 10+ 函数添加完整类型注解
- 🎯 10 个常量提取 (字符串 + URL)
- 🔧 降低认知复杂度,拆分复杂方法
- 🔒 移除不安全的
eval(),替换为基于 AST 的安全表达式解析器 - ⏱️ 为所有 HTTP 请求添加 30 秒超时,防止脚本挂起
- 📦 锁定依赖版本,确保构建一致性
- 🏗️ 新增
RenewalBot类封装全局状态,提高可测试性 - 🧪 添加 21 个单元测试覆盖核心功能
- 📝 添加类型注解和
LogLevel枚举统一日志格式 - ⚡ OCR 实例缓存,避免重复加载模型
- 📧 支持自定义
SMTP_HOST和SMTP_PORT环境变量 - ✅ 新增启动时配置验证,明确提示缺失项
- 通过 GitHub Actions 自动续约 Euserv 免费 VPS。
- 处理登录、会话及两步验证(2FA)。
- 双保险验证码识别:优先使用本地 OCR (
ddddocr),失败后自动切换到 TrueCaptcha API。 - 通过 IMAP 连接 Gmail 邮箱,自动获取续约 PIN 码。
- 完整实现包含 Token 验证的精确续约流程。
- 每次运行后通过邮件发送状态报告。
- 所有凭据均通过 GitHub Secrets 安全管理。
要使此项目正常工作,请严格遵循以下步骤。
- 一个正常使用的 Euserv 免费 VPS 账户。
- 一个 Gmail 邮箱账户,并已为其生成一个应用专用密码。
- (可选) 一个 TrueCaptcha 账户 (
apitruecaptcha.org),作为本地 OCR 失败时的备用方案。 - 一个 GitHub 账户。
点击本页面右上角的 Fork 按钮,将此项目复制到您自己的 GitHub 账户下。
安全建议:请确保您没有在任何时候意外地将个人凭据提交到代码中。
这是最关键的步骤。请进入您 Fork 后的仓库,点击 Settings -> Secrets and variables -> Actions,然后点击 New repository secret 按钮,逐一添加以下 Secret:
| Secret 名称 | 示例值 | 描述 |
|---|---|---|
EUSERV_USERNAME |
your_euserv_username |
用于登录 Euserv。 |
EUSERV_PASSWORD |
your_euserv_password |
用于登录 Euserv。 |
EUSERV_2FA |
ABCD1234EFGH5678 |
(可选) 您在 Euserv 后台开启 2FA 时获得的Setup key。 |
CAPTCHA_USERID |
your_captcha_userid |
(可选) 您在 TrueCaptcha 注册的 userid,作为本地 OCR 的备用。 |
CAPTCHA_APIKEY |
xxxxxxxxxxxxxxxxxxxx |
(可选) 您的 TrueCaptcha apikey,作为本地 OCR 的备用。 |
EMAIL_HOST |
imap.gmail.com |
您的邮箱 IMAP 服务器地址。 |
EMAIL_USERNAME |
your_email@gmail.com |
您的完整邮箱地址。 |
EMAIL_PASSWORD |
abcd efgh ijkl mnop |
您的邮箱应用专用密码。 |
NOTIFICATION_EMAIL |
your_notify_email@example.com |
用于接收运行报告的邮箱地址。 |
SMTP_HOST |
smtp.gmail.com |
(可选) 手动指定 SMTP 服务器。若不提供,将尝试从 IMAP 配置推断。 |
SMTP_PORT |
587 |
(可选) 手动指定 SMTP 端口。默认为 587。 |
PAT_WITH_WORKFLOW_SCOPE |
github_pat_xxxx |
(推荐) 用于动态调度的 Fine-grained PAT。需设置权限:Contents (RW) 和 Workflows (RW)。 |
请务必确保 Secret 名称与上表完全一致,并将示例值替换为您自己的真实信息。
关于 2FA: 强烈建议您在 Euserv 后台开启 2FA。这不仅能极大地增强您账户的安全性,还很有可能让服务器信任您的登录行为,从而跳过图片验证码识别,为您节省 API 调用费用。
- 点击仓库顶部的
Actions标签页。 - 在左侧选择
Euserv VPS Renewal工作流。 - 点击
Run workflow按钮来手动触发一次运行。 - 您可以点击运行中的任务,实时查看日志输出。
脚本默认在请求 PIN 码后等待 30 秒 再去邮箱中读取。如果您的邮件接收有延迟,可以修改 Euserv_Renewal.py 文件顶部的 WAITING_TIME_OF_PIN 常量,例如改为 60。
脚本采用动态调度机制:
| 特性 | 说明 |
|---|---|
| 动态调度 | 续约完成后自动更新 cron 为下次续约日期,只在需要时运行,零额外消耗 |
| 失败重试 | 失败后每 30 分钟重试,最多 3 次 |
| 跨天续试 | 当天全部失败后,第二天自动继续尝试 |
| PAT 要求 | 需要配置 PAT_WITH_WORKFLOW_SCOPE Secret 以启用动态调度 |
创建 PAT:创建 Fine-grained Token
- Repository access: 选择
Only select repositories-> 选择本仓库 - Permissions: 展开并设置
Contents为 Read and write,Workflows为 Read and write
该项目根据 GNU General Public License v3.0 许可证授权。详情请参阅 LICENSE 文件。
- 本项目按"原样"提供,作者不对任何因使用此脚本可能导致的服务中断、数据丢失或其他损失负责。
- EUserv 随时可能更改其网站结构或续约流程,这可能导致此自动化脚本失效。
- 请自行承担使用风险。
- 🔴 Fix CAPTCHA failure: Fixed an issue where
sess_idwas not synchronized during the first login attempt, causing CAPTCHA submission to fail - 🔴 Enhance email retry capability: IMAP connection drops or auth exceptions now trigger conditional retries instead of crashing immediately on temporary network issues
- 🔴 Fix status email misinformation: When smart scheduling skips renewal (not due yet), the email report is explicitly marked as "Skipped" instead of falsely reporting "Success"
- 🟡 Fix renewal status override: Added
_safe_refresh_session()to prevent a session refresh failure from overwriting a successful renewal status
- 🛡️ Unified request origin: Unified all
Originheaders tohttps://support.euserv.comto prevent potential WAF blocks - 🔧 Build system: Added
pyproject.tomlfor standardizing environments and pytestpythonpath(removedsys.pathhacks), cleaned up redundant return values
- 🔴 Session expiry auto-recovery: Added
_refresh_session()method to re-login after long renewal flows, preventing_check_post_renewal_statusfailures due to expired sessions - 📧 Email encoding compatibility:
_extract_email_body()now usespart.get_content_charset()with UTF-8 fallback, supporting multiple email encodings
- 🔧 Simplified
_handle_captchaparameters (7→3), reads credentials from instance directly - 🔧 Simplified
_handle_2faparameters (3→1), inlines origin header to preserve originalhttps://www.euserv.com - 🔧 Changed
_renewreturn type frombooltoNone(was always returning True) - 🔧 Extracted
SERVER_LIST_RETRY_DELAYconstant, replacing hardcodedsleep(30) - 🗑️ Removed redundant
http://retry adapter (Euserv is exclusively HTTPS)
- ✅ Fixed test name
test_parentheses_not_supported→test_parentheses_work - 🧹 Removed unused
pytestimport fromtest_safe_eval.py
- ⚡ Enabled Node.js 24 to silence GitHub Actions deprecation warning
v2.2.0 and earlier
- 🔴 Fix cron schedule not updating: Empty server list now returns
EXIT_FAILUREand saves debug HTML - 🔴 Fix next_cron lost after renewal: Always output next renewal date regardless of post-renewal status
- 🔴 Fix test suite: Resolved ImportError in 3 test files caused by function renaming
- 🔒 Mask 2FA codes and PINs in logs (show only last 2 digits)
- 🛡️ Added
HTTPAdapter+Retrystrategy for automatic retries on 5xx errors - 🌐 Updated User-Agent to Chrome 131
- 🎯 Use
ddddocr.set_ranges()to constrain character set for better math CAPTCHA accuracy - 🧹 Extracted
_clean_math_expr()/_try_solve_math()for unified math expression handling - 🧹 Extracted
_parse_server_row()to reduce cognitive complexity - 📊 Added row count logging for server list parsing; save HTML on empty results for debugging
- 🏗️ Phase 3 Architecture Unification: Moved 15+ top-level functions into
RenewalBotclass - 🧹 Eliminated global variables
LOG_MESSAGES,CURRENT_LOGIN_ATTEMPT,_ocr_instance - ⚡ OCR Prewarming: Preload model at startup to reduce first recognition delay
- 🔒 HTTP Session Resource Management: Added
_cleanup()method for proper closure
- 🧪 Added pytest test suite (
tests/test_renewal.py) - 🎯 9 test classes covering core functionality
- 📝 10+ functions with complete type annotations
- 🎯 10 constants extracted (strings + URLs)
- 🔧 Reduced cognitive complexity by splitting complex methods
- 🔒 Replaced unsafe
eval()with AST-based safe expression parser - ⏱️ Added 30-second timeout to all HTTP requests
- 📦 Locked dependency versions for consistent builds
- 🏗️ Added
RenewalBotclass to encapsulate global state - 🧪 Added 21 unit tests covering core functionality
- 📝 Added type annotations and
LogLevelenum for unified logging - ⚡ Cached OCR instance to avoid reloading model
- 📧 Support for custom
SMTP_HOSTandSMTP_PORTenvironment variables - ✅ Added startup config validation with clear error messages
- Automated renewal of Euserv free VPS via GitHub Actions.
- Handles login, sessions, and Two-Factor Authentication (2FA).
- Hybrid CAPTCHA solving: Uses local OCR (
ddddocr) first, falls back to TrueCaptcha API if needed. - Retrieves renewal PINs from a Gmail account via IMAP.
- Implements the complete and precise renewal workflow, including token exchange.
- Sends a run status report to your email after each execution.
- All credentials are managed securely via GitHub Secrets.
Please follow these steps carefully to get the workflow running.
- An active Euserv Free VPS account.
- A Gmail account for which you have generated an App Password.
- (Optional) A TrueCaptcha account (
apitruecaptcha.org) as a fallback for local OCR. - A GitHub account.
Click the Fork button at the top-right of this page to copy this project to your own GitHub account.
Security Recommendation: Please ensure you have not accidentally committed any personal credentials to the codebase at any time.
This is the most critical step. Navigate to your forked repository, go to Settings -> Secrets and variables -> Actions, and click New repository secret to add each of the following secrets:
| Secret Name | Example Value | Description |
|---|---|---|
EUSERV_USERNAME |
your_euserv_username |
Your username for EUserv. |
EUSERV_PASSWORD |
your_euserv_password |
Your password for EUserv. |
EUSERV_2FA |
ABCD1234EFGH5678 |
(Optional) The Setup key you get when enabling 2FA in your Euserv account. |
CAPTCHA_USERID |
your_captcha_userid |
(Optional) Your userid from TrueCaptcha, used as fallback for local OCR. |
CAPTCHA_APIKEY |
xxxxxxxxxxxxxxxxxxxx |
(Optional) Your apikey from TrueCaptcha, used as fallback for local OCR. |
EMAIL_HOST |
imap.gmail.com |
Your email provider's IMAP server. |
EMAIL_USERNAME |
your_email@gmail.com |
Your full email address. |
EMAIL_PASSWORD |
abcd efgh ijkl mnop |
Your email App Password. |
NOTIFICATION_EMAIL |
your_notify_email@example.com |
The email address to receive status reports. |
SMTP_HOST |
smtp.gmail.com |
(Optional) Manually specify SMTP server. Infers from IMAP if not provided. |
SMTP_PORT |
587 |
(Optional) Manually specify SMTP port. Defaults to 587. |
PAT_WITH_WORKFLOW_SCOPE |
github_pat_xxxx |
(Recommended) Fine-grained PAT for dynamic scheduling. Permissions: Contents (RW) and Workflows (RW). |
Ensure the secret names are copied exactly and replace the example values with your own real information.
About 2FA: It is highly recommended to enable 2FA in your Euserv account. Not only does it significantly improve your account security, but it may also cause the server to trust your login and skip the image CAPTCHA, saving you API costs.
- Go to the
Actionstab in your repository. - Select the
Euserv VPS Renewalworkflow from the sidebar. - Click the
Run workflowbutton to trigger a manual run. - You can click on the running job to view the live logs.
By default, the script waits for 30 seconds after requesting a PIN before checking your email. If you experience email delays, you can edit the WAITING_TIME_OF_PIN constant at the top of the Euserv_Renewal.py file (e.g., set it to 60).
The script uses a dynamic scheduling mechanism:
| Feature | Description |
|---|---|
| Dynamic Schedule | Automatically updates cron to next renewal date after completion, zero overhead |
| Retry on Failure | Retries every 30 minutes on failure, up to 3 times |
| Cross-day Retry | Automatically retries the next day if all attempts fail |
| PAT Required | Requires PAT_WITH_WORKFLOW_SCOPE Secret for dynamic scheduling |
Create PAT: Create Fine-grained Token
- Repository access: Select
Only select repositories-> Select this repository - Permissions: Set
Contentsto Read and write,Workflowsto Read and write
This project is licensed under the GNU General Public License v3.0. See the LICENSE file for details.
- This project is provided "as is". The author is not responsible for any loss of service, data, or other damages that may result from its use.
- EUserv may change its website structure or renewal process at any time, which could break this automation.
- Use at your own risk.