1 Introduction
When deploying a WordPress active-active node solution, a crucial technical point isread-write separation: that is, routing all operations involving ”writing to the database” (such as publishing posts, modifying content, modifying plugin configurations, submitting comments, etc.) to theprimary write nodefor completion, while other nodes serve as read-only replicas, providing content display, caching services, etc. The benefits of this architecture are obvious:
- It avoids data conflicts, synchronization delays, and consistency issues that may be caused by multi-point writing;
- It also reduces the load pressure on the primary database, allowing each node to perform its respective duties, thereby improving the scalability and stability of the overall system.
The core of implementing read-write separation lies inaccurately and stably guiding all front-end requests that may trigger write operations to the primary write node. For certain write operations, such as administrators publishing posts, modifying content, or configuring plugins, these behaviors usually occur in the backend operation environment and can be bypassed by forcing access to the primary write node, making them relatively controllable. However, there are also some write behaviors that are difficult to intervene in manually, such as visitors posting comments directly under an article. These requests occur on ordinary pages, and users cannot be expected to specifically jump to a dedicated node to complete the operation, making them uncontrollable.
Based on the above description, in the WordPress active-active node architecture,how to handle the write path of comment requests is one of the most challenging problems when implementing read-write separation, and is also the key to the overall architectural design. The most direct approach in the early days was theto force all user comment requests to be routed to the primary node's database for writing, ensuring data source consistency and centralized management. To achieve this goal, common approaches include:
- Cross-domain writing solution: Configure CORS headers in the primary node's WordPress to allow other read-only nodes to submit comments directly to the primary node (e.g., comment.tangwudi.com) via JavaScript AJAX requests. This method is relatively simple to implement, but involves browser cross-domain restrictions, requiring proper configuration of response headers such as Access-Control-Allow-Origin and handling Cookie scope issues.
- Reverse proxy write-back solution: In the Web Server of each read-only node, reverse proxy the user's POST requests to admin-ajax.php or wp-comments-post.php to the primary node. This method is transparent to users, requires no modification of front-end code, and has no cross-domain issues. However, in practice, attention must be paid to details such as session persistence and cache penetration; otherwise, issues like lost authentication or CSRF validation failure can easily occur.
- Worker transit solution: intercepting comment requests using edge computing platforms like Cloudflare Worker and forwarding them uniformly to the primary node. This method allows for flexible centralized control of the backend write path without modifying client-side code, while naturally possessing the advantages of cross-origin shielding and security isolation.
2 Implementation method based on ”cross-origin writing”
Implementing a cross-origin-based solution is actually not complicated. Taking my blog (which uses the Argon theme) as an example, the comment requests were originally sent to “https://blog.tangwudi.com/admin-ajax.php“, and with just a slight modification at the PHP layer to change the request address to “https://comment.tangwudi.com/admin-ajax.php“, comment traffic can be directed to the designated node to achieve centralized writing. However, this solution comes with several potential pitfalls that deserve special attention:
- Browser same-origin policy restrictions
By default, browsers block web pages from making requests with cookies to servers of different origins (i.e., different domains, protocols, or ports). This means that if the front-end page attempts to send a comment request to another subdomain of the primary write node, it may be rejected by WordPress due to a lack of credentials, especially in scenarios where the user is logged in or CSRF validation is required.
- CORS configuration is difficult to unify
To achieve cross-origin requests, the target node (i.e., the primary write node) needs to correctly set CORS headers, such as Access-Control-Allow-Origin, Access-Control-Allow-Credentials, etc. Although this can technically be done by adding these response headers via PHP or server configuration, in a multi-node environment, to ensure unified code maintenance, all nodes also need to maintain the same configuration, even if some read-only nodes do not handle write requests themselves.
- Security introduces new risks
When cross-origin requests are allowed, improper settings can easily lead to security risks such as API exposure, privilege bypass, or CSRF attacks. For example, setting Access-Control-Allow-Origin: * and allowing cookies will directly lead to the risk of session credential leakage.
- Debugging and monitoring become complex
Once a cross-origin request fails, the browser side often only throws a vague CORS error, with the specific details hidden in the network layer, making it difficult to locate and troubleshoot the issue. At the same time, log records will also be distributed across multiple nodes, increasing the difficulty of operations and maintenance.
- Compatibility and edge behaviors are unpredictable
Certain caching layers (such as Cloudflare APO), front-end frameworks, or plugins may assume by default that all requests are same-origin. Cross-origin solutions can easily trigger abnormal behaviors, such as CSRF token invalidation, loss of user state, and functional errors.
In summary, although the cross-origin-based solution is technically feasible, it involves a certain level of complexity regarding authentication, caching, security, and code uniformity. In multi-node deployment scenarios, unless you have the ability to strictly control cross-origin access behavior, it is generally recommended to choose this solution more cautiously. Personally, I wouldn't choose this one; it looks like it would take a lot of hassle~~.
Note: For friends who are unfamiliar with the concept of ”cross-origin”, you can refer to the relevant description in one of my previous articles ”Home Data Center Series: A Review of Core Web Development Concepts Starting from Ajax Cross-Origin Issues (Non-Programmer's Perspective)”
3 Implementation method based on ”reverse proxy write-back”
Another common approach is to implement the write-back of comment requests through the ”reverse proxy” of the Web Server layer. Specifically, rules can be set in the Web Server (such as Nginx or Nginx Proxy Manager based on it) of each read-only node to reverse proxy specific POST requests to admin-ajax.php to the primary write node, for examplehttps://comment.tangwudi.com/admin-ajax.php. From the browser's perspective, the request is still sent to the original domain name (such as https://blog.tangwudi.com/admin-ajax.php), but is actually taken over by the Web Server to complete the ”traffic redirection” of the request.
The advantage of this approach lies in its simple structure and flexible deployment. It neither requires browser support for cross-origin access nor introduces additional middleware tools. As long as the reverse proxy is configured properly, the entire process is completely transparent to front-end users and the WordPress plugin layer. It can even coexist with APO and CDN caching, without involving complex Worker routing logic.
However, it also presents some detailed challenges, mainly focusing on the following aspects:
- Cookie and session persistence: Whether requests after the reverse proxy can carry the user's login status depends on whether the Cookie domain is configured correctly and whether the primary write node recognizes these Cookies;
- Cache interference: If the front-end or CDN caches requests to admin-ajax.php, it may cause the proxied requests to fail to reach the primary write node. Cache-Control and related policies must be set with caution;
- Difficulty in troubleshooting: Once a request is intercepted or fails to rewrite at the proxy layer, troubleshooting may not be as intuitive as with a Worker, especially when there is no obvious error in the UI layer;
- Only applicable to HTTP layer forwarding: It cannot perform complex request rewriting, response reorganization, or identity pass-through, offering less room for operation compared to Workers.
Overall, this approach is closer to the ”traditional reverse proxy” concept, suitable for users who already have Nginx management experience and wish to complete the modification at the existing Web Server layer. It is also a technical solution for ”processing write requests at the node edge,” with simple deployment and no intrusion into the main WordPress structure, making it a reliable means of achieving read-write separation.
4 Implementation method based on ”Worker transit”
Using this method can completely bypass cross-origin related issues, because from the browser's perspective, comment requests are still initiated to the original domain name, such as “ in this example.“https://blog.tangwudi.com/admin-ajax.php“. The Worker will intercept such requests and forward them at the edge network node to another node that is actually responsible for write operations, such as “https://comment.tangwudi.com/admin-ajax.php“, thereby achieving centralized comment writing.
The biggest advantage of this approach is that it is completely transparent to the front-end, requiring no modification of browser-side logic, nor does it require the client to support CORS or configure complex cross-origin headers. It also avoids exposing the actual address of the write node, enhancing security.
Of course, there are also some points to note with this solution, such as:
- Cloudflare Worker has upper limits on CPU execution time and response size. Although comment requests usually do not trigger these limits, they still require attention;
- What the Worker proxies is HTTP layer request forwarding, and cannot handle certain advanced scenarios that require maintaining long connections or state synchronization with the origin site (such as real-time WebSockets, specific Cookie domain attribute issues);
- If you have enabled APO (Automatic Platform Optimization), the Worker's processing may conflict with its caching strategy. You need to specifically set the Worker's routing match rules to avoid interfering with the page cache maintained by APO.
Overall, Worker is a very elegant concept for ”solving cross-origin write issues outside the node,” especially suitable for WordPress multi-active deployment scenarios to orderly route ”user-generated data” to the sole primary write node.
5 Using the ”Worker transit” method to achieve comment consistency across active-active WordPress nodes
1 Using Worker to unify comment reads and writes to the primary node
This solution has the simplest and most direct logic, following the concept of “all operations uniformly go through the primary node.” Whether it is comment submission, backend management operations, or front-end page display, all requests point to the primary WordPress node located on the macmini in the home data center (corresponding to the domain name comment.tangwudi.com).
The specific process is as follows:
- Comment writing: When a user submits a comment, the request is routed to the primary node, which processes it and returns the result, allowing the user to see the comment take effect instantly.
- Page reading: Whether accessing via the intranet or public network, all page content (including the comment list) is read directly from the primary node, ensuring that the content displayed on the front-end is consistent with the latest state of the database.
- Secondary node role: The secondary node is only used for backup or observation purposes, does not participate in real-time reading and writing, does not need to synchronize the database, and does not affect the user experience.
The advantages of this design are:
- Read-write consistency: All comments and data displayed on the front-end come from the primary node, avoiding issues of lost comments or inconsistent display caused by secondary node latency.
- Simple logic: No need for multi-node writing or complex database synchronization mechanisms, reducing maintenance costs.
- Good user experience: Front-end users always see the latest data without waiting for secondary node synchronization.
I have already written about the specific Worker creation steps in many previous articles, so I won't repeat them here. Other than configuring the Worker routing correctly, there is not much else to set up. Taking my blog as an example, the Worker's entry route is:
blog.tangwudi.com/wp-admin/admin-ajax.php*

Different WordPress themes do not use exactly the same technical methods to implement comment functions. Taking the Argon theme as an example, it uses an AJAX-based asynchronous submission method, so comment submission requests are ultimately sent to WordPress's “/wp-admin/admin-ajax.php” interface and processed through the backend's wp_ajax_nopriv_* hook. The advantage of this method is that users do not need to refresh the page after submitting comments, resulting in a smoother experience.
However, many themes (especially some native, lightweight themes) adopt the default WordPress comment handling mechanism, which is to POST comments directly to wp-comments-post.php. Although this method is more traditional, it usually triggers a full page refresh after submission, resulting in a slightly inferior user experience. In addition, because these requests do not go through the AJAX pipeline, it is not easy to capture submission results or unify error handling logic on the front-end.
This difference requires special attention in actual architectural design, especially when deploying custom Workers, reverse proxies, or Webhook processing logic. If you only intercept or rewrite one submission path while ignoring the possibility of the other, it may cause comments on some themes to fail to write or fail to write successfully. Therefore, in multi-node deployment scenarios, it is recommended to adapt to different comment submission entry points based on the actual theme and comment plugin used, ensuring that all paths can be correctly routed or processed. For the sake of laziness, I only consider the ”admin-ajax.php” case here, as I cannot verify ”wp-comments-post.php” anyway.
The specific Worker code is as follows:
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
// 仅处理评论提交请求
if (
url.pathname !== "/wp-admin/admin-ajax.php" ||
request.method !== "POST"
) {
return fetch(request);
}
// 判断是否为评论请求
const reqBody = await request.arrayBuffer();
const contentType = request.headers.get("content-type") || "";
let isCommentRequest = false;
if (contentType.includes("application/x-www-form-urlencoded")) {
try {
const bodyText = new TextDecoder().decode(reqBody);
const params = new URLSearchParams(bodyText);
isCommentRequest = params.has("comment_post_ID") && params.has("comment");
} catch (err) {
console.log("Body parse failed:", err);
}
}
if (!isCommentRequest) {
return fetch(request);
}
// 固定代理到主节点
const targetUrl = "https://comment.tangwudi.com/wp-admin/admin-ajax.php";
const headers = new Headers(request.headers);
headers.delete("referer");
const proxiedRequest = new Request(targetUrl, {
method: "POST",
headers,
body: reqBody,
redirect: "manual"
});
const response = await fetch(proxiedRequest);
const respHeaders = new Headers(response.headers);
respHeaders.set("X-Worker-Hit", "yes");
respHeaders.set("X-Worker-Mode", "primary-only");
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: respHeaders
});
}
};
In the above Worker code, I have added two small features to enhance the controllability and observability of proxied requests. These two small features not only improve debugging efficiency but also make the entire comment request proxy chain more transparent and verifiable:
- Clear original Referer: To avoid exposing the source information of the original page (i.e., blog.tangwudi.com) to the target server, I explicitly deleted the Referer field in the request header within the Worker. This helps improve privacy protection to some extent and can also prevent certain server-side logic from rejecting requests due to inconsistent Referers (actually, it's not very useful for my scenario because I removed the default domain access restrictions on all WordPress nodes), especially when WordPress security plugins, WAFs, or certain CDN policies are present.
- Add custom response header X-Worker-Hit: To make it easier to confirm whether the request actually went through the Worker, I added the header ”X-Worker-Hit: yes” to the response headers. With this header, you can quickly determine whether the Worker is active in browser developer tools or debugging tools like curl, avoiding misjudgments caused by route misses, cache bypasses, etc. When the path does not match, the Worker will also return a 404 with X-Worker-Hit: no, making it easy to distinguish whether the processing path is correct.
2 Implementation of simultaneous comment writing to multiple nodes
2.1 Changing ”single-point writing” to ”simultaneous writing”
On the basis of having achieved “writing comments to the primary node,” I have further designed and implemented Cloudflare Worker Multi-point Synchronous Writing Solution: During the comment submission stage, the Worker will initiate requests to both the primary node and the secondary node simultaneously, achieving write redundancy, thereby balancing data security and high availability。
Specifically, this solution has several technical highlights:
- Concurrent Writing: Comment requests are replicated at the edge layer; the primary node processes user operations, while the secondary node asynchronously receives the replica without blocking the front-end experience.
- Redundancy Guarantee: Even if the primary node is temporarily unavailable, the secondary node still retains complete comment data, enhancing the system's disaster recovery capability.
- Read-write consistency: The primary node still serves as the sole ultimate data source, ensuring that comment auto-increment IDs and display order do not conflict, while the secondary node's data can be used for backup or observation purposes.
- Strong Scalability: This solution is not only applicable to dual-node environments but can also be extended to multi-node WordPress deployments, providing a practical reference for future multi-region architectures.
In this way, Worker not only solves the write conflict issue in traditional multi-node WordPress environments, but also brings edge computing and high-availability design to life in personal blog-level architectures.
2.2 Worker code for the specific implementation
Assuming the primary node corresponds to ”comment1.tangwudi.com” and the Chicago secondary node corresponds to ”comment2.tangwudi.com”, the specific Worker code is as follows:
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
// 仅拦截 WordPress 评论提交
if (
url.pathname !== "/wp-admin/admin-ajax.php" ||
request.method !== "POST"
) {
return fetch(request);
}
// 缓冲请求体
const reqBody = await request.arrayBuffer();
const contentType = request.headers.get("content-type") || "";
const isForm = contentType.includes("application/x-www-form-urlencoded");
// 判断是否为评论请求
let isCommentRequest = false;
if (isForm) {
const params = new URLSearchParams(new TextDecoder().decode(reqBody));
isCommentRequest = params.has("comment_post_ID") && params.has("comment");
}
if (!isCommentRequest) {
return fetch(request);
}
// 通用请求头
const headers = new Headers(request.headers);
headers.delete("referer"); // 避免跨域问题
// 主节点与副节点地址
const primaryURL = "https://comment1.tangwudi.com/wp-admin/admin-ajax.php";
const secondaryURL = "https://comment2.tangwudi.com/wp-admin/admin-ajax.php";
// 构造请求
const primaryReq = new Request(primaryURL, {
method: "POST",
headers,
body: reqBody,
redirect: "manual"
});
const secondaryReq = new Request(secondaryURL, {
method: "POST",
headers,
body: reqBody,
redirect: "manual"
});
// 发起主节点请求(同步)
const primaryResponse = await fetch(primaryReq);
const clonedBody = await primaryResponse.clone().arrayBuffer(); // clone body 以便后续返回
const respHeaders = new Headers(primaryResponse.headers);
respHeaders.set("X-Worker-Hit", "yes");
// 并发异步任务(副本写入 + Webhook 通知)
ctx.waitUntil(
Promise.allSettled([
fetch(secondaryReq).catch(err =>
console.log("Secondary write failed:", err)
),
primaryResponse.ok
? fetch("https://notifysanjose.tangwudi.com/webhook/comment", {
method: "POST",
headers: { "X-Webhook-Token": "tangwudi19790624200271" }
}).catch(err => console.log("Webhook failed:", err))
: Promise.resolve()
])
);
return new Response(clonedBody, {
status: primaryResponse.status,
statusText: primaryResponse.statusText,
headers: respHeaders
});
}
};
| Goal | Implementation Method |
|---|---|
| Return response after successful writing to the primary node | await fetch(primaryRequest) |
| Secondary node writes asynchronously; failure does not affect the main process | ctx.waitUntil(fetch(secondaryRequest)) |
| Keep Worker responding quickly | All non-main process operations go through ctx.waitUntil() |
| Support dual-writing of comments and simplify data synchronization | A single submission synchronizes both nodes, eliminating the need for subsequent detection mechanisms |
To achieve comment writing across multiple WordPress nodes, after receiving a comment request, the Worker script does not simply forward it to a single node, but insteadconstructs multiple concurrent HTTP requests, sending the same comment datato both the primary node and the secondary node simultaneously”s interfaces. These requests are typically triggered asynchronously, independent of each other, and do not affect one another. Leveraging the high availability of edge computing, this “multi-point concurrent writing" solution balances performance, reliability, and consistency, significantly reducing the impact of primary node single points of failure or synchronization delays on user experience.
Note 1: This method can support adding more nodes in an active-active WordPress architecture, such as comment3.tangwudi.com, comment4.tangwudi.com, etc., with simple code modifications.
Note 2: Multi-point synchronous writing improvesdisaster recovery capability and redundancy guarantee, but correspondingly increasescomplexity, latency, and operation and maintenance costs, making it suitable for scenarios pursuing high availability or multi-node architectures, while actually of little significance for ordinary personal blogs.
Although implementing simultaneous WordPress multi-node comment writing via Worker significantly improves the availability and consistency of the comment system under an active-active architecture, it still cannot bypass a fundamental limitation of WordPress:Comment moderation status and comment IDs only take effect in the local database, and the primary and secondary nodes are unaware of each other。
The problem this brings is not just ”needing to approve on the primary node and synchronize the database after a comment is first published“, but more critically:if a visitor subsequently attempts to reply to a comment, and the ID of that comment is inconsistent across different nodes (because the node accessed during APO caching or origin-pull is uncontrollable, whether the comment content on the page comes from the primary node or the secondary node, the comment ID is inconsistent for the other party. This pitfall troubled me for a long time because at that time I did not fully understand the ”auto-increment” logic of relational databases), errors such as ”cannot reply to unapproved comment” or ”referenced ID does not exist” may occur。
The reason is simple: WordPress's comment reply logic relies on the unique ID of the existing comment, and this ID is independently generated via auto-increment in each node's database. If the primary and secondary nodes are not synchronized, the ID allocation on each node may deviate,leading to a successful reply on one node but an error and failure on another。
To solve this problem, I adopted a relatively safe strategy:All comment moderation and replies are handled uniformly on the primary node. Once the operation is complete, a database synchronization from the primary node to the secondary node is immediately triggered manually. This ensures that comment data and status remain consistent across all nodes, avoiding interaction errors and achieving a ”fast and stable” comment writing experience under an active-active architecture.
Although exporting wordpress.sql every time a comment is approved or replied to is a bit like ”moving the entire database just to sync one comment,” under the current premise of low comment volume, this ”lightweight manual synchronization” is still a highly cost-effective choice:Compared to reconstructing the entire comment system or introducing external platforms, this is clearly more pragmatic and transparent.
Of course, this is only a temporary solution. After all, the volume of comments is still small. If it really grows bigger and stronger in the future with many daily comments, then I will have to consider restoring the previous ”database change perception + automatic synchronization” mechanism—by then, it would be a happy problem of growth. :)
Note: Actually, I could also consider syncing only the wp_comments table instead of the entire database, but I'm currently too lazy to maintain two different scripts, so I'm just cutting corners.
6 New comment notification (optional)
1 Ramblings
I have actually always been somewhat dissatisfied with WordPress's built-in email notifications for new comments. Usually, my phone is on silent most of the time, and almost all notifications are turned off. I only check my email when I'm in a good mood, so it often takes several hours or even half a day before I realize someone has left a comment on my blog. This sense of delay is quite terrible for someone who wants to run a blog seriously and maintain timely interaction with readers.
Taking advantage of the opportunity to route comment requests through Cloudflare Worker this time, I thought, why not upgrade the notification mechanism as well: when a new comment is generated, push the notification directly via Bark (friends unfamiliar with Bark can refer to the article:Docker Series: Building a Message Push Server Based on Bark Server) to my phone and the Mac mini at home, so that I can know someone has left a comment within seconds.
However, I also ran into a bit of trouble here: compared to server-side shell scripts, cron jobs, or webhook-like methods, Worker itself runs on edge nodes, is stateless, and is event-driven. The lighter the processing logic, the better. It is not very suitable for directly making Bark requests that contain identity keys: this is both a security consideration and to keep the Worker as simple as possible.
Therefore, I plan to have the Worker, after capturing a comment request, send a notification signal to a lightweight Webhook interface pre-deployed on another 1-core 1G RAM VPS node in San Jose. The responsibility of this interface is very single: it does not directly call Bark, but acts as a transit station to pass the event to a locally running shell script. The script is pre-configured with Bark's API Key and push templates, and is truly responsible for precisely pushing notifications to my phone and Mac mini.
This design, on one hand, keeps sensitive keys in a trusted local environment without exposing them to the Worker side, avoiding potential security risks; on the other hand, it also allows me to flexibly control notification behavior, such as filtering keywords based on comment content, merging duplicate notifications, and even adding notification throttling logic to avoid being bombarded by comments in a short period of time.
At the same time, the combination of Webhook + local script is also very easy to extend: in the future, if I want to switch to Telegram Bot, WeChat Work, or desktop pop-up reminders, I only need to make minor modifications at the script level without touching a single line of Worker code. Overall, this is a solution that balances real-time performance, security, and maintainability quite well.
2 4. Implementing a lightweight local Webhook with Python Flask
2.1 Introduction to Flask
When using the BT Panel before, I noticed that there was a ready-made Webhook software in BT's app store that could be installed directly, which was very convenient and trouble-free. But now I have switched to the 1panel panel. After some searching, there seems to be no similar ready-made plugin or application available (there are actually many friends online requesting this feature from 1panel, and it's been years~), so I had to write one myself. Considering that the requirements should be as lightweight, easy to maintain, and flexibly extensible as possible, I finally chose to build this local Webhook service based on Python's Flask framework.
Flask is a very popular lightweight Web framework with only a few thousand lines of core code. It is designed to be simple and flexible, making it suitable for quickly developing various Web services and interfaces: it does not have overly complex dependencies or forced project structures, allowing developers to freely organize code and functions according to actual needs. In addition, Flask has rich extension library support, making it easy to integrate databases, authentication, logging, and other functions. If needed in the future, it can also be easily expanded. Its community is active, documentation is complete, and it is very easy to get started with, making it perfect for building small services like a local Webhook.
2.2 Flask installation
apt update
apt install -y python3-pip
pip3 install flask
2.3 Creating a Flask-based Webhook service script
Create a new directory
mkdir -p ~/script
Create the service script
cd ~/script
vim webhook_server.py
Paste and save the following code:
# filename: webhook_server.py
from flask import Flask, request
import subprocess
app = Flask(__name__)
# 预设 Webhook Token
EXPECTED_TOKEN = "your-token"
@app.route("/webhook/comment", methods=["POST"])
def comment_webhook():
# 校验 Token
received_token = request.headers.get("X-Webhook-Token", "")
if received_token != EXPECTED_TOKEN:
return "Invalid token", 403
# 调用 Bark 通知脚本
try:
subprocess.run(["/usr/local/bin/bark_notify.sh"], check=True)
return "Bark notified", 200
except subprocess.CalledProcessError as e:
return f"Notification failed: {str(e)}", 500
if __name__ == "__main__":
# 监听 IP 和指定端口
app.run(host="127.0.0.1", port=9527)
Above is an example of a Python Webhook service written using the Flask framework. It listens for POST requests on the /webhook/comment path on port 9527 of ”127.0.0.1" and triggers the local script (/usr/local/bin/bark_notify.sh) to execute the Bark notification logic.
As for the bark_notify.sh script, it is created according to the following process:
vim /usr/local/bin/bark_notify.sh
Copy, paste, and save the following content (please modify according to your actual environment):
#!/bin/bash"bark_success_macmini">/dev/null"bark_success_iphone" > /dev/null
vim /root/script/update-smartdns-china.sh
chmod +x /usr/local/bin/bark_notify.sh
The reason for creating bark_notify.sh under the path /usr/local/bin is out of consideration for permissions and accessibility. Although the script is essentially just a simple notification trigger, in actual deployment, Flask applications do not always run as the root user. Especially in production environments, Flask is more likely to be started as www-data, nobody, or a regular user specified through systemd.
If the script is placed in the “/root” directory, the Flask process may not be able to access or execute the script in that path due to permission restrictions, resulting in a failed notification trigger, and it is not easy to directly detect the problem in the logs (this issue took me several hours to troubleshoot; previously, for convenience, I placed it directly under the ”/root/script” path, which kept returning an internal 500 error). In contrast, ”/usr/local/bin” is a location reserved in Linux systems for user-defined executables. It has appropriate execution permissions by default, and most users and services can directly find commands or scripts under this path in the PATH environment variable, making it more secure and universal.
In short:/usr/local/bin is a reasonable placement point that balances permissions, security, and system maintainability, making it suitable as a unified entry point for system-level service invocation scripts.
2.4 The notification part of the Worker code
This part of sending Webhook notifications only needs to be appended after the `ctx.waitUntil` content of the previous Worker code, as shown in the following example:
// 并发从节点请求,但不影响主流程
ctx.waitUntil(
fetch(secondaryRequest).catch((err) => {
console.log("Secondary write failed:", err);
})
);
// 成功时发送 Webhook 通知(非阻塞)
if (primaryResponse.ok) {
ctx.waitUntil(
fetch("https://notification.tangwudi.com/webhook/comment", {
method: "POST",
headers: {
"X-Webhook-Token": "your-token"
}
}).catch((err) => {
console.log("Webhook failed:", err);
})
);
}
ctx.waitUntil(
7 Afterword
fetch(secondaryRequest).catch((err) => {
console.log(”Secondary write failed:”, err);})与);// Send Webhook notification on success (non-blocking)
if (primaryResponse.ok) {ctx.waitUntil(fetch("https://notification.tangwudi.com/webhook/comment", {