


[{"content":"","date":"2026-06-10","externalUrl":null,"permalink":"/categories/logs/","section":"Categories","summary":"","title":"Logs","type":"categories"},{"content":"","date":"2026-06-10","externalUrl":null,"permalink":"/logs/","section":"Logs","summary":"","title":"Logs","type":"logs"},{"content":" 写在前面 # 这篇文章并没有评价某一段关系或者审判某个人的意思，我更想记录的是在我旁观了我朋友和他女朋友吵架并闹到分手的过程中，我观察到了我朋友的一种行为模式：\n一个人可以不断说出“正确的话”，不断宣布自己“懂了”，“成长了”，“成熟了”，但是如果底层的结算目标没有改变，那么所谓的感悟只是进行了语言层面上的更新，而不是系统层面的升级。\n事件背景：一次次不断重复的“顿悟” # 我的朋友在他的亲密关系中不断感受到痛苦，他认为自己已经为她付出的够多了，为什么没有得到相应的回报。\n后来，我了解到，他的付出不是纯粹的为了让对方开心，而是带着一种隐性的回报期待：我这样对你好，你也应该以某种方式回应我。当这种期待没有被满足时，付出就不再只是付出，而会变成关系里的压力。\n我向他说明了这点，他反复复盘，反复道歉，反复说自己“我懂了”。\n一开始，我也以为他真的明白了。\n但随着时间推移，我发现了一些现象：\n他对他女朋友道歉的内容永远是“我错了”“我不好”“我有罪”，他好像没有提到他对对方造成了什么困扰。 对方明确的表示不想和他说话，但是他依旧是“我错了”“我不好”“我有罪”。 我告诉他爱别人首先要爱自己，他告诉我“他懂了”。 一周后他也累了，他渐渐放宽了对对方的“情感轰炸”和“道歉”，发现了对方愿意跟他沟通了。 他顿悟了，他认为他的痛苦来源于他对对方的情感要求过高，并立志打算以后“不纠缠”和“爱自己”。 于是我开始怀疑了：他到底是真的改变了，还是换了一套听起来更正确的话术？\n“被通知”的礼物：付出为什么会变成压力 # 他维系爱情和友情的一大方式是送礼物。\n送礼物当然没有问题，但如果每次送礼都要提前通知、强调、制造期待，那么礼物就不但是礼物了。\n它会变成：\n我重视你的证明。 我们关系之间的凭证 我需要你立刻看见我对你的好 我希望你回应我的情绪账单 礼物还没收到手里，对方心里先开始承担心理压力了。\n这让我意识到，这并不只是他在亲密关系中的问题，而是一种更普遍的相处方式：他做很多事情并不是做完就结束，而是需要被看见、被回应、被确认。\n感悟表演：他把“说出来”当成”做到了“ # 他的一个明显特点是：只要有一点新的想法，就会立刻说出来，发给很多人，等待别人对他的感悟的回应。\n比如 “我懂了。”\n“我成熟了。”\n“我知道问题在哪了。”\n“我以后不会这样了。”\n“我要开始爱自己了。”\n这些话本身可能不假，但问题在于：他把说出这些话当初一种成长。\n他在刚开始的时候告诉我他对成熟的定义：\n出去和对象玩可以把事情安排的很妥当，让对方不用操心行程。 吃饭的时候汤洒到他对象衣服上可以让他对象别慌，他来解决这个事情。 遇到航班取消了，可以很好的安排行程，不慌不乱。 但是我认为真正的成熟应该是：\n情绪上来的时候，不再继续发信息量为0的长文。 被拒绝时，真的做到不打扰对方 道歉时，不再要求被伤害的人接受自己的愧疚。 说“爱自己”之后，即使没人看见，也正常过自己的生活 但在为看来，他更像是把感悟广播出去，然后通过外部反馈获得“我已经成长了”的确认。\n这也是为什么我后来对他的“新感悟”越来越不敏感，因为类似的话一周前也出现过，只是换了一个新的说法。\n这算一种感悟表演吧\n不是完全没有感悟，但是仅仅停留于语言层。\n“正确的话”服务错误的动机 # 他观察到对方在他停止轰炸后愿意沟通了，但与此同时他本打算过好自己的生活，于是他顿悟了：\n比如 “我发现爱自己可以让自己变得很有魅力”； “不要把太多情感寄托在别人身上” ； “我不会再纠缠了”； “我要开始提升自己了”； “我要给她单独的个人空间”\n最让我警觉的，就是他说了很多正确的话。\n这些话但看起来都挺对，但如果结合他的目的，它们的功能变了：\n“我爱自己”不是因为我本来就应该好好生活，而是因为我变好了，她可能会重新回来。 他把“我不寄托太多感情在她身上”当成工具，目的是为了更好的把情感寄托在她身上。 “我尊重她”不是因为她本来就应该被尊重，而是因为尊重她可以让我重新获得进入她生活的资格。 他发现了自己痛苦的原因了，他的改变是为了让自己没有那么痛苦，他给别人带来痛苦呢？ 于是，语言正确了，但结算对象没有改变。所谓“爱自己”“尊重她”“不纠缠”，仍然在围绕着同一个目的转：让她回来。\n当朋友成为他叙事里的工具 # 事情真正越界的地方，不在于他用正确的话把旧目的包装起来了，而是他把其他人放到了他的挽回计划里。\n他一边对他女朋友说：“xxx跟我一起来的上海，要不要一起见一面”。 他一边又对我这个朋友说：“我女朋友想要见你，想通过你了解我最近到底怎么想的，我这一辈子的幸福可就靠你了啊！”\n而我当时在干嘛：凌晨2点在别的城市陪他聊天，他让我早上8点坐飞机去上海。\n也就是说，他同时在向两边同时提供加工过的信息。\n这也是我后来真正生气的原因：不是因为他难过，不是因为他想挽回，而是因为他未经同意使用了别人的名字、身份和信誉。\n他擅自的把本该自己承担的后果，转移到了我的身上，让我觉得\n如果我拒绝去上海，就是我在毁掉他们两个的感情。\n他同样让我觉得\n如果我坚守了自己的底线，就是我对不起他。\n道歉为什么也会成为新的情绪负担 # 这里还有一种更隐蔽的消耗：他伤害了别人（无论是他女朋友还是我），然后来道歉，但道歉本身就是一种情绪。\n他擅长于发“我错了”“对不起”“我真的很后悔”“我对不起你”“我不好”。\n这些话看起来是在认错，但焦点仍然可能停留在他的愧疚、他的后悔、他的痛苦上。\n真正的道歉应该是：\n我看见了我对你造成了什么伤害。 我承认这是我做的不对。 我尽量去补偿对对方的损失。 我之后会用什么行为避免再次发生这样的事情。 而他：\n“我都已经向你道歉了，你还想怎么样呢？”\n被伤害的人，还得继续接着伤害者的愧疚。\n如果你回复他了，他会给你说“我错了”，如果你不理他，他会给你刷屏“我错了”\n这也是我后来理解为什么他女朋友要跟他闹矛盾了：原来最累的不是对方犯错，而是对方犯错之后，受伤的人还要承接他的崩溃、反思和道歉情绪，然后反过来哄他，这本来是不必要的消耗。\n我后来意识到，他的行为需要观众：\n送礼需要观众 顿悟需要观众 爱自己需要观众 不纠缠需要观众 痛苦需要观众 他的事情可以不做，但是不能没有被注意到。\n底层行为模式：高表达，低兑现 # 如果让我对他的行为做出总结，我会证明认为：\n把表达当成行动：说“我顿悟了”，好像就等于已经改变了。 被看见之后行动已经结算：别人听见了、回应了、认可了，这件事才算完成。 把关系当成自我确认系统：别人回应他，他才确认自己是好的、成熟的、有价值的。 用正确的话维护旧系统：话术升级了，但底层目的没有改变。 因此我想到一句话：\n语言更新了，但是系统没有升级。\n回到自己：把“分析了”当成“做到了” # 如果文章通篇讲他，那也没什么意思了，我从他身上也隐隐看到了自己的问题。\n他用表达代替行动。\n而我喜欢用分析代替行动。\n形式不同，风险相似。\n就像这篇文章一样，我确实做这么多分析会有一种“我已经进步”的感觉。\n还有一种“还好他有的问题我没有”的高高在上的视角。\n我曾经也一度“顿悟”，并雄心壮志的为自己规划了路线，可能我和他的区别就是我不会说出来给别人。\n但是我会仔细的制定计划，每天看着这份计划单就很满足，但是计划单只是计划单，我看着它，而不做任何事情。\n真正的升级永远在下一次运行的时候 # 真正的成长不是靠嘴说出来的，也不是靠分析和做计划就能得到的。\n而是在下一次同样的问题出现时，人的系统不会复现旧的bug。\n真正的升级，从来不是因为日志打印出来了就升级成功了。\n","date":"2026-06-10","externalUrl":null,"permalink":"/logs/language-updated-system-not-upgraded/","section":"Logs","summary":"我观察到的我朋友的一些行为习惯以及自己可能存在的问题","title":"朋友的语言更新了，系统并没有升级","type":"logs"},{"content":" Introduction # This is a U.S. phone plan that does not require KYC. In mainland China, it can only use AT\u0026amp;T\u0026rsquo;s network. It includes 100 minutes of calls, 100 SMS messages, and 1 GB of data, all available internationally. In my testing, it worked very smoothly for registering a U.S. Google account. Even when phone number verification popped up, it could pass successfully.\nOperating Environment # Network environment: self-hosted U.S. proxy node. Operating system: Windows. Browser: Chrome, with normal access to the website. Purchase # Buy Redpocket\u0026rsquo;s $2.5/month plan on eBay and choose eSIM as the delivery method. The listing says it includes 200 MB of high-speed data, which refers to data within the United States. In addition, it also includes 1 GB of global roaming data.\nNotes:\nUse an address in a U.S. tax-free state as the shipping address, otherwise there will be about $2 of extra tax. The area code of the phone number you receive is determined by the region of the shipping address. About 5-15 minutes after purchase, you will receive an email containing the eSIM Confirmation Code, which is used to activate the eSIM.\nActivation # Use the activation URL in the email, then enter the Confirmation Code and your phone\u0026rsquo;s IMEI number.\nNote I used a U.S. version iPhone SE 3. I saw online that Redpocket is very strict about detecting non-native eSIM adapter cards, so using a physical eSIM adapter card may have a chance of failing.\nLog in to your Redpocket account with Google. This way, your Redpocket username will be your email address. After entering the account, change the password while you are still logged in. Otherwise, Google login may have issues later in the app, and you may only be able to log in with the account password.\nAfter activation, you will receive a QR code by email. Scan the QR code with your phone to add the eSIM.\nAbout Wi-Fi Calling # When I tried to enable Wi-Fi Calling, I attempted it three times:\nDirectly activated from mainland China without a proxy. Failed. The activation website directly showed \u0026ldquo;access denied\u0026rdquo;. Switched to my self-hosted U.S. proxy node. I could successfully enter the website, but it showed that Wi-Fi Calling could not be activated. I tried several times and got the same result. Tried using Webshare\u0026rsquo;s pseudo-residential proxy. This successfully loaded the webpage and asked me to enter an E911 address. I searched online for a random address, filled it in, and after a while Wi-Fi Calling activated successfully. To keep Wi-Fi Calling active, I am currently using a U.S. proxy node. It should not require a residential IP to stay active. My residential proxy uses the SOCKS5 protocol, which fundamentally does not support UDP, while Wi-Fi Calling is maintained over UDP at the lower layer. However, network environments vary by region, so please test yourself whether a direct connection can maintain it.\nPotential Risks of This Card # The phone number may have been recycled. The Telegram account associated with the number I received after activation had already been banned. It is possible that number ranges in tax-free-state area codes have already been abused heavily. Using an address from a non-tax-free state might be better. It is uncertain whether the $30/year plan on eBay will always remain available. If it is delisted, the cost of keeping the number will become higher. ","date":"28 May 2026","externalUrl":null,"permalink":"/en/posts/redpocket/","section":"Posts","summary":"Redpocket’s $30/year plan includes 1 GB of global roaming data, 100 minutes of global roaming calls, and 100 global roaming SMS messages. It also works smoothly for receiving verification codes on various platforms.","title":"[eSIM] Redpocket Annual $30 Plan Purchase and Activation Notes","type":"posts"},{"content":"","date":"28 May 2026","externalUrl":null,"permalink":"/en/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","date":"28 May 2026","externalUrl":null,"permalink":"/en/tags/esim/","section":"Tags","summary":"","title":"Esim","type":"tags"},{"content":"","date":"28 May 2026","externalUrl":null,"permalink":"/en/categories/networking/","section":"Categories","summary":"","title":"Networking","type":"categories"},{"content":"","date":"28 May 2026","externalUrl":null,"permalink":"/en/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":"","date":"28 May 2026","externalUrl":null,"permalink":"/en/","section":"Pyaxy's Blog","summary":"","title":"Pyaxy's Blog","type":"page"},{"content":"","date":"28 May 2026","externalUrl":null,"permalink":"/en/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":" Background # I recently bought a new soft router and configured OpenClash as a whole-home proxy. However, the network environment I use when developing on my Mac changes frequently, and I also use Surge for rewrite rules. After all, if my entire home network already uses OpenClash, then did I buy Surge for nothing? 😭 In the end, my goal was still to let Surge take over proxy handling on my computer.\nThen came the problem. The mode currently promoted by OpenClash is fake-ip mode. But in fake-ip mode, if you want to implement LAN device allowlist/blocklist filtering, the DNS hijacking mode must be changed to Firewall Forwarding, and Dnsmasq Forwarding is not supported.\nGiving up Dnsmasq forwarding means giving up OpenClash\u0026rsquo;s \u0026ldquo;bypass mainland China\u0026rdquo; feature. This feature allows traffic to popular domestic Chinese websites to avoid being processed by the Clash core, effectively reducing the load on the core while improving access speed.\nIn Dnsmasq mode, the most common way to control whether a device uses the proxy is to add this rule to OpenClash\u0026rsquo;s rule set:\nrules: SRC-IP-CIDR,192.168.1.23/32,DIRECT This does make a specific device avoid the proxy, but the downside is also obvious. Although the specific device does not use the proxy, its traffic still enters the kernel, gets unpacked, and is then wrapped and forwarded according to rules. This still increases kernel load.\nAnother drawback of fake-ip In fake-ip mode, pinging domain names from devices stops working. This is because after fake-ip mode is enabled, OpenClash adds firewall rules to reject ICMP packets in order to keep the system operating correctly, which causes ping to fail.\nTherefore, whether using Dnsmasq forwarding or firewall forwarding, neither can solve all of the problems above. So, is it possible to make all traffic from a specific device completely bypass the kernel, so that OpenClash is entirely transparent to that device when it goes online?\nThis way, whether it is a NAS or some other device, you can safely let it connect directly without worrying that its traffic will secretly be used up.\nReferences # While implementing the goal above, I referred to the following links:\nopenclash的基础设置，实现全屋代理\n# OpenWrt 使用 Tag 给特定的设备单独指定旁路网关的地址和 DNS\nOpenClash 在 Dnsmasq 转发模式下基于 MAC 绕过设备\nIntegrated Implementation # I combined and optimized the content from the documents above into the implementation tutorial below.\nHere is the system information of my soft router when this tutorial was written:\nFirmware version: ImmortalWrt 24.10.4 r33602-e717d133ed6d / LuCI openwrt-24.10 branch 25.300.72106~0418b54 Kernel version: 6.6.110 Clash core version: alpha-g86257fc OpenClash client version: v0.47.055 If you find that some Web UI elements do not match during implementation, search for the equivalent operation method for your own system version.\nAssign a Fixed IP Address to the Device # If you have already configured a DHCP static IP address for the device, skip this step.\nGo to Network -\u0026gt; DHCP/DNS -\u0026gt; Static Leases -\u0026gt; Add.\nFor MAC address, select the device\u0026rsquo;s MAC address. For IPv4 address, enter the device\u0026rsquo;s current IP address. Set Lease time to 12h, keep the rest as default, then save and apply the configuration. From now on, every time the device connects to the network, it will receive this same IP address.\nModify Source Traffic Access Control # Go to the OpenClash homepage, select Plugin Settings, scroll to the bottom, and in the Source Traffic Access Control settings area, add a new entry. Set Internal Address to the fixed IP address from earlier, leave Port empty, set Protocol to All, and set Target to RETURN. After finishing, click Apply Configuration at the bottom.\nAfter this setup, traffic from the device to real-ip addresses will bypass the kernel directly. However, the device needs DNS first in order to obtain real-ip addresses. If the device\u0026rsquo;s DNS server address is still set to the router gateway address, the kernel will still hijack DNS requests and return fake-ip addresses. Source Traffic Access Control will not make traffic to fake-ip addresses bypass the kernel. Therefore, in the next step, we need to set the device\u0026rsquo;s DNS server.\nSet the Device\u0026rsquo;s DNS Server # There are two ways to set the device\u0026rsquo;s DNS server:\nMethod 1 # Go directly into your device\u0026rsquo;s network settings and manually change the DNS server to popular domestic Chinese DNS servers, such as 114.114.114.114, 223.5.5.5, or 119.29.29.29. Personally, I recommend the second method more. Method 2 does not modify the device\u0026rsquo;s network settings, making it easier to keep the device\u0026rsquo;s network settings consistent when switching between different network environments.\nMethod 2 # This method is based on Dnsmasq\u0026rsquo;s tag feature. It can assign gateway and DNS server addresses to a specific device. Here, we only need to assign DNS server addresses.\nGo back to the page where you fixed the IP address. Edit the static lease entry you just configured, find Tag, and add one, such as directnode. The tag name must not contain spaces or special characters. Save and apply.\nEnter the OpenWrt command-line page and run the following commands:\nuci set dhcp.directnode=\u0026#34;tag\u0026#34; uci set dhcp.directnode.dhcp_option=\u0026#34;6,223.5.5.5,119.29.29.29,114.114.114.114\u0026#34; uci commit dhcp /etc/init.d/dnsmasq restart In the commands above, directnode is the tag name you created. Its type is set to tag. In dhcp_option, 6 represents the DNS server addresses to be distributed. Multiple addresses are separated directly with commas.\nDisconnect the device from the network and reconnect it. This will trigger DHCP assignment again. Check the device\u0026rsquo;s network settings. The DNS server addresses distributed by the router should no longer be the router\u0026rsquo;s address.\nIn theory, the DNS process should no longer go through the router at this point. Now the entire path, from DNS to accessing real-ip addresses, should bypass the kernel. However, if you try accessing Google at this point, you will find that your device can still access it successfully.\nModify Firewall Rules # The issue is actually caused by the router\u0026rsquo;s firewall rules. After OpenClash starts in fake-ip mode, it adds a firewall rule that hijacks all TCP/UDP requests to port 53 and redirects them to the local port 53. This means the public DNS servers configured above do not actually take effect. Requests sent by the device to public DNS servers are still hijacked and return fake-ip addresses.\nThe solution is also simple. OpenClash\u0026rsquo;s allowlist/blocklist implementation in firewall forwarding mode depends on the firewall. It maintains a set of MAC addresses for devices that need to bypass the proxy. Then, during DNS hijacking, any packet whose MAC address matches this set is passed through directly.\nWe can follow this idea and implement allowlist/blocklist behavior in Dnsmasq mode as well. In OpenClash, users can operate firewall rules through an overwrite script.\nGo to the OpenClash homepage, click Plugin Settings, then click Developer Options.\nPaste the overwrite code below and fill in the specific device MAC addresses. This code maintains a set of MAC addresses that should bypass Clash, so packets matching the set are passed through directly during DNS hijacking.\nWarning The code below modifies a firewall based on nftables. If you are using an iptables firewall, some syntax may not apply. You can ask AI to help convert the syntax.\n#!/bin/sh . /usr/share/openclash/ruby.sh . /usr/share/openclash/log.sh . /lib/functions.sh # This script is called by /etc/init.d/openclash # Add your custom overwrite scripts here, they will be take effict after the OpenClash own srcipts LOG_OUT \u0026#34;Tip: Start Running Custom Overwrite Scripts...\u0026#34; LOGTIME=$(echo $(date \u0026#34;+%Y-%m-%d %H:%M:%S\u0026#34;)) LOG_FILE=\u0026#34;/tmp/openclash.log\u0026#34; #Config Path CONFIG_FILE=\u0026#34;$1\u0026#34; sleep 20 LOG_OUT \u0026#34;Tip: Start Add Custom Firewall Rules...\u0026#34; # \u0026gt;\u0026gt;\u0026gt; Fill in the MAC addresses of devices that need to bypass Clash here, separated by spaces MACS=\u0026#34;aa:bb:cc:dd:ee:ff\u0026#34; # 1) Set: lan_bypass_macs. Flush it if it exists to ensure repeatable execution. if nft list set inet fw4 lan_bypass_macs \u0026gt;/dev/null 2\u0026gt;\u0026amp;1; then nft flush set inet fw4 lan_bypass_macs || : else nft add set inet fw4 lan_bypass_macs \u0026#39;{ type ether_addr; flags interval; }\u0026#39; || : fi # Populate the set for mac in $MACS; do # Normalize to lowercase m=$(echo \u0026#34;$mac\u0026#34; | tr \u0026#39;A-F\u0026#39; \u0026#39;a-f\u0026#39;) nft add element inet fw4 lan_bypass_macs \u0026#34;{ $m }\u0026#34; 2\u0026gt;/dev/null || : done # 2) Delete all old \u0026#34;ether saddr @lan_bypass_macs return\u0026#34; rules, then insert one at the top of the chain nft -a list chain inet fw4 dstnat 2\u0026gt;/dev/null | awk \u0026#39; /ether saddr @lan_bypass_macs/ \u0026amp;\u0026amp; / return/ { for (i=1;i\u0026lt;=NF;i++) if ($i==\u0026#34;handle\u0026#34;) {print $(i+1)} }\u0026#39; | while read -r h; do [ -n \u0026#34;$h\u0026#34; ] \u0026amp;\u0026amp; nft delete rule inet fw4 dstnat handle \u0026#34;$h\u0026#34; 2\u0026gt;/dev/null || : done nft insert rule inet fw4 dstnat ether saddr @lan_bypass_macs return || : LOG_OUT \u0026#34;Done: MAC bypass rules loaded.\u0026#34; exit 0 At this point, all traffic from your device should no longer enter the Clash core, and fake-ip should no longer affect pinging domain names either 😄.\n","date":"7 March 2026","externalUrl":null,"permalink":"/en/posts/fake-ip/","section":"Posts","summary":"Implemented per-device proxy routing in OpenClash under fake-ip with Dnsmasq forwarding.","title":"[Tutorial] Let OpenClash in fake-ip Dnsmasq Forwarding Mode Bypass the Kernel by Device MAC","type":"posts"},{"content":"","date":"7 March 2026","externalUrl":null,"permalink":"/en/tags/openclash/","section":"Tags","summary":"","title":"OpenClash","type":"tags"},{"content":"","date":"7 March 2026","externalUrl":null,"permalink":"/en/tags/soft-router/","section":"Tags","summary":"","title":"Soft Router","type":"tags"},{"content":"","date":"2026-03-7","externalUrl":null,"permalink":"/tags/%E8%BD%AF%E8%B7%AF%E7%94%B1/","section":"Tags","summary":"","title":"软路由","type":"tags"},{"content":" Background # Recently, I wanted to tinker with a NAS for building a home media library. After looking into it carefully, however, I found that both memory and hard drives were not priced very attractively. In recent years, as NAS devices have become more mainstream, ISPs have also tightened their restrictions on upload bandwidth, which gradually hurts remote playback performance.\nIt just so happened that this excellent article solved my needs quite well: 【教程】如何用一台2g15g的VPS结合网盘实现302直链播放的个人全自动追番Emby影视库\nSo I reproduced the setup by following the author\u0026rsquo;s approach, and I recorded the pitfalls I encountered along the way at the end. If you run into problems during deployment, I hope the holes I fell into can save you from falling into them again. I hope this helps!\nPreparation # Knowledge you should have:\nBasic Linux operations. Basic Docker usage. My setup:\nRaspberry Pi 5, 8 GB RAM, 32 GB storage card. 115 Cloud Drive membership. About the device Based on my experience after successfully deploying this setup, the performance of my Raspberry Pi 5 is completely overkill. Due to the characteristics of this viewing architecture, the device\u0026rsquo;s CPU usage stays at 0 most of the time, so an entry-level VPS is entirely sufficient.\nAbout cloud drives The choice of cloud drive mainly comes down to two things:\nPreferably use a domestic Chinese cloud drive. This architecture fully supports playback of Dolby Blu-ray remux movies. A movie like that is usually around 70-80 GB. If you use an overseas cloud drive, the traffic costs can be very high, and most overseas cloud drives do not provide CDN acceleration in mainland China. Preferably use one without speed limits. Playing high-bitrate videos places heavy demands on the cloud drive\u0026rsquo;s bandwidth. If your cloud drive membership is throttled, such as Quark Cloud Drive redeemed through Taobao 88 VIP, the viewing experience will be much worse. Final Result # If the setup succeeds, you can build a home media library with:\nInstant playback of 4K remux movies. Zero server bandwidth consumption, with bandwidth provided by the cloud drive provider. Final result:\nSolution Overview # Component Overview # This solution is deployed entirely with Docker containers, so it is quite portable. Understanding what each Docker container does will help us understand the full architecture.\nOpenList # OpenListTeam/OpenList\nThis is equivalent to self-hosting a cloud drive branded as OpenList on your server. You can mount other cloud drives on the market under directories in this OpenList drive. Understanding this is crucial for understanding the rest of the architecture.\nNote For example, I mounted 115 Cloud Drive under OpenList\u0026rsquo;s /115 directory, and I mounted Quark Cloud Drive under OpenList\u0026rsquo;s /Quark directory. Users only need to access the OpenList drive to access two or even more cloud drives at the same time.\nTaoSync # dr34m-cn/taosync\nTaoSync can download online content from OpenList to the server. In this setup, it is mainly used to sync the Strm files generated by OpenList to the server.\nMihomo # MetaCubeX/mihomo\nMihomo is a proxy component based on Clash.Meta. It allows the server to access websites outside the Great Firewall, mainly to solve the problem where Emby fails to fetch movie metadata.\nMetacubexd # MetaCubeX/metacubexd\nMetacubexd is the frontend dashboard for Mihomo, used to control Mihomo\u0026rsquo;s proxy nodes.\nEmby # Emby is the core of the home media library. It centrally manages resources in the media library. In this solution, it is mainly used to scan locally stored Strm files and build the media library index.\nDocker image: https://hub.docker.com/r/amilys/embyserver\nMediaLinker # thsrite/MediaLinker\nMediaLinker reverse proxies Emby and intercepts user playback requests, redirecting them to the cloud drive. It is the key to achieving zero server load during playback.\nHow the Solution Works # The core idea of this solution is to turn a lightweight VPS into a gateway for a petabyte-scale data center. All data exchanged between the user and the VPS consists of control signals. The VPS directly redirects the user\u0026rsquo;s playback request to the cloud drive, and the video traffic bypasses the VPS and goes straight to the user\u0026rsquo;s device. This greatly lowers the server hardware requirements.\nDeployment # After preparing the VPS, create a directory named my_media under the user\u0026rsquo;s home directory. All configuration for the home media library will be stored in this directory.\nDeploy OpenList # Create a docker-compose.yml file under my_media, and fill in the configuration for our first container, OpenList.\ndocker-compose.yml # services: # OpenList configuration openlist: image: openlistteam/openlist:latest # Official image container_name: openlist restart: always # Automatically restart the service if the server unexpectedly loses power ports: - 5244:5244 # Map port 5244 to the outside environment: - TZ=Asia/Shanghai # China timezone volumes: - ./openlist/data:/opt/openlist/data # Store all OpenList configuration under my_media/openlist - ./Strm:/Strm # Important! Save Strm files generated by OpenList to my_media/Strm on the host machine Mount the Cloud Drive # After editing the file, try starting the service. Enter this in the command line:\ndocker compose up -d After it starts successfully, visit http://\u0026lt;server-ip\u0026gt;:5244. You should be able to enter the OpenList main page.\nThe account is admin. The password will be printed in the terminal logs the first time OpenList starts. After logging in, change the password immediately.\nFollow OpenList\u0026rsquo;s official documentation to add the cloud drive you use. I added 115 Cloud Drive. After adding it successfully, it will appear on the homepage.\nGenerate Strm Files # A .strm file is essentially a plain text file. It does not store any video content. Instead, it only stores one or more lines containing direct access URLs for media resources, such as HTTP, HTTPS, WebDAV, SMB, or RTSP URLs.\nYou can think of it as a \u0026ldquo;video shortcut\u0026rdquo; or an \u0026ldquo;online playback pointer\u0026rdquo;.\nEmby supports reading Strm files perfectly. In Emby\u0026rsquo;s eyes, a .strm file is a media video. Therefore, we can store a large number of Strm files on a lightweight VPS with limited storage space.\nOpenList supports scanning an internal target and automatically generating corresponding .strm files for files under that directory. Go to OpenList Management -\u0026gt; Storage -\u0026gt; Add -\u0026gt; select Strm as the driver name. We need to fill in the following:\nMount path: /virtual_strm Enable signature: enabled. Path: the path of the cloud drive you mounted in OpenList. For example, I mounted 115 Cloud Drive under /115, and my media files are stored in 01_Media_Library on the cloud drive, so my full path is /115/01_Media_Library. Site URL: fill in http://\u0026lt;server-ip\u0026gt;:5244. This way, the generated direct media access URLs are external addresses, not container-internal addresses. Carry signature: enabled. After enabling this, the direct links generated by OpenList will include signatures for authentication. If your server is exposed to the public internet, make sure to enable this. It prevents someone from guessing your cloud drive directory structure and using direct links arbitrarily. After this is complete, OpenList will automatically generate .strm files for the directory you selected under /virtual_strm.\nAs expected, if we visit the link inside a .strm file in the browser at this point, it should play directly, and the server should not show any obvious traffic changes.\nNote At this stage, the .strm files are only stored inside the OpenList drive. From the VPS\u0026rsquo;s perspective, these files are still online files, while Emby only supports accessing local folders. Therefore, we need to sync the .strm files to a local folder. We use TaoSync to do this.\nDeploy TaoSync # Add TaoSync\u0026rsquo;s configuration to the docker-compose.yml we just edited.\ndocker-compose.yml # services: # OpenList configuration openlist: ... # TaoSync configuration taosync: image: dr34m/tao-sync:latest # Official image container_name: taosync restart: always ports: - 8023:8023 # Map port 8023 to the outside volumes: - ./taosync:/app/data # Store TaoSync configuration under my_media/taosync Configure the Sync Job # Start the service again. Now visit http://\u0026lt;server-ip\u0026gt;:8023, and you should enter the TaoSync main page. Similar to OpenList, the username is admin, and the password is printed in the logs. If it is not there, use the recovery key in my_media/taosync to change the password.\nTaoSync is essentially used to operate cloud drives and does not support operations on local files. However, we can mount another path of type Local Storage in OpenList. Again, go to OpenList Management -\u0026gt; Storage -\u0026gt; Add -\u0026gt; select Local Storage as the driver name. We need to fill in:\nMount path: /physical_strm Enable signature: enabled. Root folder path: /Strm. After saving, we should now see the physical_strm directory in OpenList, and it should be empty.\nEnter TaoSync, go to Engine Management -\u0026gt; Add Engine, and fill in:\nAddress: the OpenList entry address, namely http://\u0026lt;server-ip\u0026gt;:5244. Remark: fill in anything you like. Token: in OpenList, go to Management -\u0026gt; Settings -\u0026gt; Other -\u0026gt; the token at the very bottom of the page. Copy it and paste it here. Next, go to Job Management -\u0026gt; Create Job, and fill in:\nEngine: the engine you just created. Source directory: the directory storing the generated strm files, namely /virtual_strm. Target directory: the directory to sync to, namely the local storage directory /physicial_strm that we just created. Sync method: full sync. This way, files deleted in the cloud will also be deleted locally. Sync interval: 10 minutes. Adjust this based on your own needs; this time is only for reference. After finishing, click manual execution on the right side of the job to perform the initial sync. After it finishes, enter OpenList\u0026rsquo;s /physical_strm directory. It should now contain the strm files generated earlier.\nDistinguishing the various strm folders (click to expand) This was one of the things that confused me a lot when I first started building the setup. From the beginning of deployment until now, three strm folders have appeared: /Strm, /virtual_strm, and /physical_strm.\nTo make their scopes easier to distinguish, I use a network-protocol-like prefix for these folders:\nVPS:// means this directory is physically stored on the server, no different from any other folder on the server. OpenList:// means this directory is only visible inside OpenList. It is similar to content in other cloud drives. Changes you make there will not affect local files on the server, just like creating a folder in a cloud drive has no effect on your computer. Now let\u0026rsquo;s talk about what happens when these strm directories work together.\nAfter we add OpenList://virtual_strm, OpenList automatically generates the same directory structure as OpenList://115/01_Media_Library under this directory, and creates a strm file for each media file. This is the initial set of strm files. After we configure OpenList://physical_strm, because of how OpenList\u0026rsquo;s local storage directory works, OpenList mounts the VPS://my_media/Strm folder onto OpenList://physical_strm. When we operate on OpenList://physical_strm, we are actually operating on VPS://my_media/Strm. When we use TaoSync to sync OpenList://virtual_strm with OpenList://physical_strm, TaoSync keeps OpenList://physical_strm consistent with OpenList://virtual_strm. And when OpenList://physical_strm is operated on, strm files are also written into VPS://my_media/Strm. At this point, we have successfully created strm files for the content on the cloud drive and stored them locally.\nNow, if you upload another video to the cloud drive, its strm file will appear in the server-side my_media/Strm directory 10 minutes later. Clicking the link in the strm file in a browser should also play directly.\nDeploy Emby # Emby is personal media server software. Once deployed on the server, it can organize media resources scattered across local hard drives, a NAS, or remote storage into a unified media library with posters, descriptions, and actor information, and provide online playback through clients.\nContinue writing the Emby configuration in docker-compose.yml.\ndocker-compose.yml # servicces: # OpenList configuration openlist: ... # TaoSync configuration taosync: ... # Emby configuration embyserver: image: amilys/embyserver_arm64v8:latest # Image for ARM architecture container_name: emby network_mode: bridge # Use bridge mode environment: - UID=0 - GID=0 - TZ=Asia/Shanghai - HTTP_PROXY=http://192.168.31.164:7890 - HTTPS_PROXY=http://192.168.31.164:7890 - http_proxy=http://192.168.31.164:7890 - https_proxy=http://192.168.31.164:7890 - NO_PROXY=localhost,127.0.0.1,openlist,medialinker - no_proxy=localhost,127.0.0.1,openlist,medialinker volumes: - ./emby/config:/config - ./Strm:/data/Strm # Map the local VPS://Strm target into the container ports: - 7568:8096 # Map Emby port to 7568 restart: always Pay attention to your server architecture Since my Raspberry Pi uses the ARM architecture, my Emby image is also the ARM image. Please choose the correct image based on your server architecture:\nFor ARM servers, use the same configuration as mine. For x86 servers, use amilys/embyserver:latest as the image. Create a Media Library # After running Docker again, visit http://\u0026lt;server-ip\u0026gt;:7568 to enter Emby\u0026rsquo;s homepage. The first startup requires initialization. Follow the prompts on the page.\nAfter creating an account and logging in, go to Settings -\u0026gt; Library -\u0026gt; New Library:\nContent type: choose TV Shows for anime/TV-series directories; choose Movies for films. Folder: choose /data/Strm/Movies or /data/Strm/TV_Shows, depending on your media library structure. I recommend storing media by type. Keep the other settings as default. Emby is a fairly complex system, so there is plenty to tinker with later. After creating it successfully, it should look like the image below. At this point, videos should be playable from the homepage. CPU usage should be maxed out, and the server should show obvious upload and download traffic. If playback fails, that is most likely because the browser\u0026rsquo;s decoding ability is too weak.\nIn addition, your media library may fail to load poster images and other metadata. This is most likely because the websites used to fetch this data are blocked by the Great Firewall. Next, we will deploy a proxy service on the server to solve this problem.\nDeploy Mihomo and Metacubexd # Mihomo is a new-generation proxy software based on the Clash.Meta core. Since servers usually do not have a GUI, we also need to deploy Metacubexd to control Mihomo.\ndocker-compose.yml # services: # Some previous configuration ...... # Mihomo configuration mihomo: image: metacubex/mihomo:latest container_name: mihomo restart: always network_mode: host volumes: - ./mihomo/config:/root/.config/mihomo # Store Mihomo configuration under my_media/mihomo/config cap_add: - NET_ADMIN # Grant network permissions to avoid errors # Metacubexd configuration metacubexd: image: dzlx/metacubexd:latest container_name: metacubexd restart: always ports: - \u0026#34;8088:80\u0026#34; # Web access port; change it to whatever you like Configure the Proxy Service # Since the proxy is only needed to fetch media metadata, the requirements for the proxy service are very low. I use a common low-cost proxy provider. Download the provider\u0026rsquo;s configuration file to ~/my_media/mihomo/config/config.yaml on the server.\nA simple approach Since subscription links provided by proxy providers are generally downloaded as Base64-encoded configuration files, we can first convert the subscription and then download it.\nSearch for any subscription conversion website. I use https://acl4ssr-sub.github.io/ here. Select basic mode, paste your proxy subscription link directly, click to generate the subscription link, and copy it. Enter this in the server terminal: curl -L -o ~/my_media/mihomo/config/config.yaml \u0026quot;the subscription download link you just generated\u0026quot; Check the downloaded configuration file and make sure it starts with the following content. If not, you need to add it yourself.\nRun Docker again, then visit http://\u0026lt;server-ip\u0026gt;:8088 to enter the Mihomo management page and configure node selection and related settings.\nMake the Emby Server Use the Proxy # Edit docker-compose.yml again and add these environment variables to Emby\u0026rsquo;s configuration:\nservices: ... ... ... # Emby configuration Emby: ... environment: ... - HTTP_PROXY=http://\u0026lt;server-ip\u0026gt;:7890 - HTTPS_PROXY=http://\u0026lt;server-ip\u0026gt;:7890 - http_proxy=http://\u0026lt;server-ip\u0026gt;:7890 - https_proxy=http://\u0026lt;server-ip\u0026gt;:7890 - NO_PROXY=localhost,127.0.0.1,openlist,medialinker - no_proxy=localhost,127.0.0.1,openlist,medialinker Restart Docker. Now the media library page should display posters and other information perfectly.\nDeploy MediaLinker # When we play videos directly through Emby, because of Emby\u0026rsquo;s own behavior, even if Emby obtains the direct link for the video the user wants to watch, it still acts as a relay itself, fetching the content from the direct link and forwarding it to the user. This results in very high CPU usage on the server, along with a large amount of upload and download traffic. Too expensive.\nMediaLinker was created for this. MediaLinker is the Docker version of embyExternalUrl, designed to reverse proxy Emby through nginx.\nWhen a user initiates a playback request, MediaLinker intercepts the request and calls Emby\u0026rsquo;s API to obtain the direct playback URL. Once it succeeds, it returns that URL directly to the user. At this point, the direct link target is OpenList. The user directly accesses OpenList\u0026rsquo;s direct link. After OpenList receives the request, it looks up the database/cache based on the direct link, determines which file in which storage backend it corresponds to, such as Aliyun Drive, OneDrive, 115, Baidu Netdisk, and so on, then calls the corresponding official cloud drive API to obtain the resource\u0026rsquo;s official direct link. This is usually something like https://cdn.115.com/xxx/xxx/xxx?sign=xxxx\u0026amp;expires=10000. These links are usually only valid for a limited time and differ each time they are obtained. OpenList then returns this link to the user via a 302 redirect, and the user successfully establishes a data flow from the user directly to the cloud drive CDN.\nContinue writing docker-compose.yml.\ndocker-compose.yml # services: # Some previous configuration ... ... ... # MediaLinker configuration medialinker: image: thsrite/medialinker:latest container_name: medialinker restart: always network_mode: host # Note that Host mode is used; Host performs better under high concurrency environment: - SERVER=emby - NGINX_PORT=8091 # From now on, we will access Emby through ip:8091 - NGINX_SSL_PORT=8095 - AUTO_UPDATE=false volumes: - ./medialinker:/opt Configure MediaLinker # After running the Docker service, MediaLinker will automatically generate the configuration file ~/my_media/medialinker/constant.js. Configure the following fields. If you have no special requirements, the rest can remain unchanged.\nconst embyHost = \u0026#34;http://\u0026lt;server-ip\u0026gt;:7568\u0026#34;; # The exposed Emby port const embyApiKey = \u0026#34;xxxxxxxxxxxxx\u0026#34;; # In Emby -\u0026gt; Settings -\u0026gt; API Keys -\u0026gt; New API Key, generate one and copy it here const mediaMountPath = [\u0026#34;\u0026#34;]; # Leave this empty Restart the Docker service again. This time, visit http://\u0026lt;server-ip\u0026gt;:8091 to enter Emby. Now click a video to play it, and you will be pleasantly surprised to find that CPU usage and upstream/downstream traffic are almost both 0.\nOf course, I personally do not recommend watching Emby directly in the browser. There are many mature media players on the market that support Emby. When adding the Emby service, remember to use port 8091 for the address.\nProblems I Encountered During Deployment # Emby Exits on First Run with Code 555 # This is caused by a system architecture mismatch. Remember to choose an image that matches your machine!\nEmby Does Not Show Video Posters # 90% of the time this is a network problem. Follow the tutorial above to deploy Mihomo and make Emby use the proxy.\nAfter the Server Loses Power and Reboots on the Home LAN, None of the Services Can Be Reached # Try checking whether the server\u0026rsquo;s IP address changed in your router\u0026rsquo;s admin page. It is best not to let the server use DHCP. Assign a static IP to the server in the router\u0026rsquo;s admin interface, and remember to update the Site URL in OpenList\u0026rsquo;s Strm configuration accordingly.\nExisting Clash Frontend Pages on the Internet Cannot Connect # This is most likely because the server address uses the HTTP protocol and is blocked by the browser. If possible, it is best to enable HTTPS on the server.\nAfter Deploying Mihomo, Emby Metadata Fetching Still Does Not Go Through the Proxy # This is usually because the metadata URL is not included in the rules. The common solution is to add the timed-out address to the rules, or switch the proxy to whitelist mode, where only addresses in the whitelist connect directly and all others go through the proxy.\nEverything Seems Configured Correctly, but Playback Still Fails # Check whether cookies and similar credentials for the cloud drive in OpenList have expired. Do not assume that being able to view the file list in OpenList means you can play the files. Cloud drive providers are stricter with APIs for viewing content. The way to verify whether a cookie has expired is to open a file in OpenList. If it has expired, a message will be displayed.\nPlayback Returns Error 401 # This is usually because OpenList has signature enabled, but the visitor\u0026rsquo;s request does not carry a signature.\nThere are two solutions:\nRecommended: enable the Carry signature option in the storage driver that generates strm files. After enabling it, it is best to manually sync once in TaoSync, if you do not want to wait 10 minutes. Use with caution in public network environments: go to OpenList Management -\u0026gt; Settings -\u0026gt; Global -\u0026gt; Sign All and turn it off. Also disable signature features for all storage drivers, and disable the password for the storage driver you are accessing. Services Stop Working After Disconnecting from the Server # Docker was run without -d, so no daemon process was created.\nSummary # After all the tinkering above, we managed to deploy an Emby project on a lightweight server that can play 4K Blu-ray remux movies. Only control signals are exchanged between the user and the server; the data stream goes directly through the cloud drive.\nThe advantage of this solution is that playback outdoors can still run at full speed. You do not need to use your own server\u0026rsquo;s upload bandwidth for data transfer. In addition, most cloud drives support instant-transfer/deduplication features, saving time when collecting resources.\nThe disadvantages are also obvious: you need a domestic cloud drive membership without speed limits, and you cannot watch anything when the network is disconnected.\nFinally, here are a few resource sites I personally use:\n【Paid】DoMi｜HD media sharing platform｜Contains a large number of Blu-ray remux concert videos and high-resolution music｜Mainly focuses on Japanese songs\n【Free】Yinfans｜Long-running 4K Blu-ray remux movie sharing platform\n【Free】Mikan Project｜One of the most complete anime resource sites\n【Free】SeedHub｜A relatively comprehensive resource site\n【Free but requires login】NULLBR｜Currently has nearly 120k+ movies and 45k+ TV series. 99% provide magnet download links. 70k+ cloud drive shares\n","date":"30 January 2026","externalUrl":null,"permalink":"/en/posts/new_media/","section":"Posts","summary":"After quite a bit of tinkering, I managed to deploy an Emby setup on a lightweight server that can play 4K Blu-ray remux movies.","title":"[Tutorial] Because I Could Not Afford More Storage, I Built a Home Media Library with a Raspberry Pi, 115 Cloud Drive, and Strm Files: A Pitfall Log","type":"posts"},{"content":"","date":"30 January 2026","externalUrl":null,"permalink":"/en/tags/115-cloud-drive/","section":"Tags","summary":"","title":"115 Cloud Drive","type":"tags"},{"content":"","date":"2026-01-30","externalUrl":null,"permalink":"/tags/115%E7%BD%91%E7%9B%98/","section":"Tags","summary":"","title":"115网盘","type":"tags"},{"content":"","date":"30 January 2026","externalUrl":null,"permalink":"/en/tags/docker/","section":"Tags","summary":"","title":"Docker","type":"tags"},{"content":"","date":"30 January 2026","externalUrl":null,"permalink":"/en/tags/emby/","section":"Tags","summary":"","title":"Emby","type":"tags"},{"content":"","date":"30 January 2026","externalUrl":null,"permalink":"/en/tags/openlist/","section":"Tags","summary":"","title":"OpenList","type":"tags"},{"content":"","date":"30 January 2026","externalUrl":null,"permalink":"/en/categories/projects/","section":"Categories","summary":"","title":"Projects","type":"categories"},{"content":"","date":"30 January 2026","externalUrl":null,"permalink":"/en/tags/raspberry-pi/","section":"Tags","summary":"","title":"Raspberry Pi","type":"tags"},{"content":"","date":"2026-01-30","externalUrl":null,"permalink":"/tags/%E6%A0%91%E8%8E%93%E6%B4%BE/","section":"Tags","summary":"","title":"树莓派","type":"tags"},{"content":" This is my new hugo blog # ","date":"9 January 2026","externalUrl":null,"permalink":"/en/posts/hello-world/","section":"Posts","summary":"","title":"Hello World","type":"posts"},{"content":"","externalUrl":null,"permalink":"/en/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","externalUrl":null,"permalink":"/en/series/","section":"Series","summary":"","title":"Series","type":"series"}]