Overview

This article explains how to build and package the Headscale source code yourself, and covers common errors that may occur during the build process along with their solutions.

  • OS: Windows 11 Home (Chinese edition); WSL 2 with Ubuntu 24.04 LTS. The build was performed on Ubuntu 24 installed via WSL 2.
  • Source directory: C:\Users\XXX\Documents\develop\0me\headscale. Source code stored on the Windows filesystem.
  • Source download: https://github.com/juanfont/headscale
  • Version: v0.26.1

Prerequisites

Downloading the Code

It is recommended to clone the repository using git rather than downloading a zip archive. When I tried to build from a zip archive, many errors appeared. I was ultimately able to produce an executable via go build -o headscale ./cmd/headscale, but make build could not complete successfully.

Use the following commands to download the source:

1
2
3
4
git clone https://github.com/juanfont/headscale.git

# Check out the v0.26.1 tag
git checkout -b release-v0.26.1 v0.26.1

Then copy config-example.yaml from the root directory and rename it to config.yaml.

WSL

Enable WSL and install the Ubuntu distribution.

In your Windows user directory (e.g. C:\Users\XXX), create a .wslconfig file with the following content:

1
2
3
4
5
6
7
8
9
[wsl2]
nestedVirtualization=true
ipv6=true
[experimental]
autoMemoryReclaim=gradual # gradual | dropcache | disabled
networkingMode=mirrored
dnsTunneling=true
firewall=true
autoProxy=true

Then restart WSL. This allows the Ubuntu environment to share your host machine’s VPN connection — which is required during the build, as many dependencies need to be downloaded from the internet.

Installing Nix

Install the Multi-user edition of nix using the root account.

1
sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon

Reference: https://nixos.org/download/

Building

Switch from the root account to a regular user account before building.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Enter the directory. Windows paths are accessible under /mnt/c/ in WSL
cd /mnt/c/Users/XXX/Documents/develop/0me/headscale

# Set up the build environment
nix develop

make generate
make test
make build

# Check the output
ls -la result/

# Verify the version
cd ./result/bin
./headscale version # prints the version number

Setting up the environment takes a while — please be patient.

Once make build completes successfully, a result directory will appear in the project folder. When viewed from Windows it appears as a 0 KB file, but it is actually a directory in the Linux filesystem.

r
wr

Running

The compiled headscale binary can be run directly on the development machine. The following describes how to copy it to another server and run it there.

  • Target server: Ubuntu 22.04 Server
1
2
3
4
5
6
7
8
9
10
# Inspect the binary using ldd or file
ubuntu@VM-16-7-ubuntu:~/doc/headscale$ ldd headscale
linux-vdso.so.1 (0x00007ffc991a1000)
libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x000079e2a91e5000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x000079e2a91e0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x000079e2a8e00000)
/nix/store/vbrdc5wgzn0w1zdp10xd2favkjn5fk7y-glibc-2.40-66/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x000079e2a9201000)
ubuntu@VM-16-7-ubuntu:~/doc/headscale$ file headscale
headscale: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /nix/store/vbrdc5wgzn0w1zdp10xd2favkjn5fk7y-glibc-2.40-66/lib/ld-linux-x86-64.so.2, stripped
ubuntu@VM-16-7-ubuntu:~/doc/headscale$

From the console output above, we can see that headscale requires /nix/store/vbrdc5wgzn0w1zdp10xd2favkjn5fk7y-glibc-2.40-66/lib/ld-linux-x86-64.so.2 at runtime. This path is symlinked to /lib64/ld-linux-x86-64.so.2. For the program to run correctly, you need to manually create the /nix/store/vbrdc5wgzn0w1zdp10xd2favkjn5fk7y-glibc-2.40-66/lib/ directory and copy ld-linux-x86-64.so.2 into it.

In addition, a config.yaml file is required, along with the directories /root/.headscale/ and /var/lib/headscale/, which must be created and granted appropriate permissions.

1
2
3
4
5
6
7
8
9
10
11
12
# Start command: headscale serve

ubuntu@VM-16-7-ubuntu:~/doc/headscale$ sudo ./headscale serve
2025-08-05T17:20:01+08:00 INF Opening database database=sqlite3 path=/var/lib/headscale/db.sqlite
2025-08-05T17:20:01+08:00 INF Using policy manager version: 2
2025-08-05T17:20:01+08:00 INF Starting Headscale commit=6b6daf389bd11624c4036de525740a0568d5f72f-dirty version=6b6daf3-dirty
2025-08-05T17:20:01+08:00 INF Clients with a lower minimum version will be rejected minimum_version=v1.62.0
2025-08-05T17:20:01+08:00 INF github.com/juanfont/headscale/hscontrol/derp/server/derp_server.go:106 > DERP region: {RegionID:999 RegionCode:headscale RegionName:Headscale Embedded DERP Latitude:0 Longitude:0 Avoid:false NoMeasureNoHome:false Nodes:[0xc00051a090]}
2025-08-05T17:20:01+08:00 INF github.com/juanfont/headscale/hscontrol/derp/server/derp_server.go:107 > DERP Nodes[0]: &{Name:999 RegionID:999 HostName:124.232.181.156 CertName: IPv4:124.232.181.156 IPv6:2406:da18:d4c:c000:8d2b:1775:f73f:7c2f STUNPort:3478 STUNOnly:false DERPPort:8081 InsecureForTests:false STUNTestIP: CanPort80:false}
2025-08-05T17:20:01+08:00 INF STUN server started at [::]:3478
2025-08-05T17:20:01+08:00 INF listening and serving HTTP on: 0.0.0.0:8080
2025-08-05T17:20:01+08:00 INF listening and serving debug and metrics on: 0.0.0.0:9090

Packaging as a Docker Image

If you want to package the source into a Docker image, refer to the following link:

https://ownding.com/2025/08/08/headscale%E7%B3%BB%E5%88%97%EF%BC%9A%E5%A6%82%E4%BD%95%E5%B0%86%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E7%9A%84headscale%E6%89%93%E5%8C%85%E6%88%90docker%E9%95%9C%E5%83%8F/

Build Error Reference

All of the following errors occurred when building from a downloaded zip archive. None of these issues appear when building from a git clone.

Issue 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Following the official build steps with nix. make test succeeds, but make build fails with the error below:
djc@jetron-djc:/mnt/c/Users/DJC/Documents/develop/0me/headscale-0.26.1$ make build
nix build
error:
while calling the 'derivationStrict' builtin
at <nix/derivation-internal.nix>:37:12:
36|
37| strict = derivationStrict drvAttrs;
| ^
38|

while evaluating the derivation attribute 'name'
at /nix/store/qmm7hgw60vp7vj9lma95hl329d0j3n6n-source/pkgs/stdenv/generic/make-derivation.nix:438:13:
437| // (optionalAttrs (attrs ? name || (attrs ? pname && attrs ? version)) {
438| name =
| ^
439| let

(stack trace truncated; use '--show-trace' to show the full, detailed trace)

error: attribute 'dirtyShortRev' missing
at /nix/store/wrx2gzxp6f5sdha4kswnpn6j8sqmfbnk-source/flake.nix:15:41:
14| }: let
15| headscaleVersion = self.shortRev or self.dirtyShortRev;
| ^
16| commitHash = self.rev or self.dirtyRev;
make: *** [Makefile:20: build] Error 1
  • Solution:

Edit the flake.nix file.

Change headscaleVersion = self.shortRev or self.dirtyShortRev; to:

1
2
3
4
5
headscaleVersion = if self ? shortRev 
then self.shortRev
else if self ? dirtyShortRev
then self.dirtyShortRev
else "v0.26.1";

Issue 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
djc@jetron-djc:/mnt/c/Users/DJC/Documents/develop/0me/headscale-0.26.1$ make build
nix build
warning: Git tree '/mnt/c/Users/DJC/Documents/develop/0me/headscale-0.26.1' is dirty
error: Cannot build '/nix/store/x0151wjd71c3icbvqrjrhmah4039cxrc-headscale-1d8abba-dirty.drv'.
Reason: builder failed with exit code 1.
Output paths:
/nix/store/w1kqv2j36dsixf5pm4v5lwf2wiwkrkhz-headscale-1d8abba-dirty
Last 25 log lines:
> Running phase: buildPhase
> Building subPackage ./cmd/headscale
> buildPhase completed in 52 seconds
> Running phase: checkPhase
>
> ----------------------------------------------------------------------
> FAIL: headscale_test.go:29: Suite.TestConfigFileLoading
>
> headscale_test.go:54:
> c.Assert(err, check.IsNil)
> ... value *fmt.wrapError = &fmt.wrapError{msg:"fatal error reading config file: open /build/headscale246087243/config.yaml: no such file or directory", err:(*fs.PathError)(0xc0003dfcb0)} ("fatal error reading config file: open /build/headscale246087243/config.yaml: no such file or directory")
>
>
> ----------------------------------------------------------------------
> FAIL: headscale_test.go:73: Suite.TestConfigLoading
>
> headscale_test.go:96:
> c.Assert(err, check.IsNil)
> ... value *fmt.wrapError = &fmt.wrapError{msg:"fatal error reading config file: Config File \"config\" Not Found in \"[/build/headscale4241716010]\"", err:viper.ConfigFileNotFoundError{name:"config", locations:"[/build/headscale4241716010]"}} ("fatal error reading config file: Config File \"config\" Not Found in \"[/build/headscale4241716010]\"")
>
> OOPS: 0 passed, 2 FAILED
> --- FAIL: Test (0.00s)
> FAIL
> FAIL github.com/juanfont/headscale/cmd/headscale 0.020s
> FAIL
For full logs, run:
nix log /nix/store/x0151wjd71c3icbvqrjrhmah4039cxrc-headscale-1d8abba-dirty.drv
make: *** [Makefile:20: build] Error 1

This error occurs because the build is interrupted by a test failure. The test fails because it cannot find the configuration file.

Build the binary directly instead:

1
2
3
cp config-example.yaml config.yaml
go mod tidy
go build -o headscale ./cmd/headscale

After a successful build, a headscale binary approximately 80+ MB in size will appear in the project directory.

Issue 3

1
2
root@jetron-djc:~# nix develop
error: experimental Nix feature 'nix-command' is disabled; add '--extra-experimental-features nix-command' to enable it

This error occurs because the nix-command feature in Nix is experimental and disabled by default.

1
2
# Edit the Nix configuration file
echo 'experimental-features = nix-command flakes' >> /etc/nix/nix.conf

Run the above command as root.

Issue 4

1
2
3
root@jetron-djc:~# nix develop
path '/root' does not contain a 'flake.nix', searching up
error: could not find a flake.nix file

This error occurs because nix develop must be run from a directory that contains a flake.nix file. cd into your project directory and run nix develop from there.

Issue 5

1
2
3
4
=== Failed
=== FAIL: hscontrol/db TestConstraints/no-duplicate-username-if-no-oidc-postgres (0.05s)
db_test.go:404: start postgres: initdb: initdb: error: cannot be run as root
initdb: hint: Please log in (using, e.g., "su") as the (unprivileged) user that will own the server process.

This error occurs because PostgreSQL’s initdb command cannot be run as root for security reasons. The test code attempts to initialize a database as root, which is rejected. Run make build as a regular (non-root) user.

Installing Dependencies Manually

1
2
3
4
5
6
# Install Buf
go install github.com/bufbuild/buf/cmd/buf@v1.55.1

# Install Protobuf
sudo apt update
sudo apt install protobuf-compiler

Purpose

To speed up Bing’s indexing of your website, you can proactively submit URLs using IndexNow.

    1. Get an API key at https://www.bing.com/indexnow/getstarted
    1. Place the key .txt file in the website root directory so it can be accessed publicly
    1. Generate a txt file containing all URLs on your site, then submit them using the script
    1. Check the submission status in Bing Webmaster Tools

Script

The following is a shell script for batch-submitting URLs to Bing IndexNow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/bin/bash

# === Configuration (modify to match your setup) ===
HOST="www.ownding.com" # Your domain
KEY="878777754f5740419ae123455c77d8ca" # Your API key
KEY_LOCATION="http://www.ownding.com/878777754f5740419ae123455c77d8ca.txt" # Key verification file URL
URL_FILE="/xxx/baidu_urls.txt" # Path to your URL file

# === Check if the file exists ===
if [ ! -f "$URL_FILE" ]; then
echo "Error: file $URL_FILE does not exist"
exit 1
fi

# === Read and process the URL list ===
# Filter blank lines, wrap in double quotes, convert to JSON array format
URLS=$(grep -v '^$' "$URL_FILE" | sed 's/.*/"&"/' | paste -sd ',' -)

echo "-------"
echo "-------"
echo $URLS
echo "-------"
echo "-------"

# === Build the JSON request body ===
JSON_BODY=$(cat <<EOF
{
"host": "$HOST",
"key": "$KEY",
"keyLocation": "$KEY_LOCATION",
"urlList": [$URLS]
}
EOF
)

echo ""
echo "-------"
echo "-------"
echo $JSON_BODY
echo "-------"
echo "-------"


# === Send the POST request ===
echo "Submitting URLs for $HOST ..."
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "https://www.bing.com/indexnow" \
-H "Content-Type: application/json; charset=utf-8" \
-d "$JSON_BODY")

# === Parse the response ===
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
RESPONSE_BODY=$(echo "$RESPONSE" | sed '$d')

if [ "$HTTP_CODE" -eq 200 ]; then
echo "Submission successful! Bing response: $RESPONSE_BODY"
else
echo "Submission failed! HTTP status code: $HTTP_CODE"
echo "Response body: $RESPONSE_BODY"
exit 1
fi

URL format inside baidu_urls.txt:

1
2
3
4
5
6
7
http://www.ownding.com/2025/06/12/%E5%9C%A8%E6%9C%89%E5%85%AC%E7%BD%91IP%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E5%A6%82%E4%BD%95%E5%AE%89%E5%85%A8%E5%9C%B0%E8%BF%9B%E8%A1%8C%E8%BF%9C%E7%A8%8B%E6%A1%8C%E9%9D%A2%E8%BF%9E%E6%8E%A5/
http://www.ownding.com/2025/06/12/%E5%9C%A8%E4%BA%91%E7%AB%AF%E9%81%A8%E6%B8%B8%EF%BC%8C%E4%BB%A3%E7%A0%81%E5%A6%82%E9%A3%9E%EF%BC%81%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%9C%E7%A8%8B%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/
http://www.ownding.com/2025/06/11/zlmediakit%E9%87%8D%E5%90%AF%E6%8B%89%E6%B5%81%E9%85%8D%E7%BD%AE%E4%B8%A2%E5%A4%B1%E4%B8%80%E7%A7%8D%E7%AE%80%E5%8D%95%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95/
http://www.ownding.com/2025/06/11/%E7%B3%BB%E7%BB%9F%E9%98%B2%E6%AD%A2%E8%BF%9C%E7%A8%8B%E6%9A%B4%E5%8A%9B%E7%A0%B4%E8%A7%A3%E6%96%B9%E6%B3%95/
http://www.ownding.com/2025/06/10/nginx%E9%85%8D%E7%BD%AEmap%E5%A4%9A%E4%B8%AA%E5%9F%9F%E5%90%8D%E8%BD%AC%E5%8F%91%E5%88%B0%E4%B8%8D%E5%90%8C%E5%90%8E%E7%AB%AF/
http://www.ownding.com/2025/06/10/ubuntu%E6%9B%B4%E6%96%B0%E6%A0%B9%E8%AF%81%E4%B9%A6/

Usage Instructions:

  1. Save the script as submit_to_bing.sh
  2. Update the configuration parameters:
    • HOST: Your website domain
    • KEY: Your Bing IndexNow API key
    • KEY_LOCATION: The URL of your key verification file
    • URL_FILE: The path to your URL file
  3. Grant execute permission:
    1
    chmod +x submit_to_bing.sh
  4. Run the script:
    1
    ./submit_to_bing.sh

OpenClaw is very popular right now. I’ve already deployed and tested it on Ubuntu and Windows Server (taking advantage of free trial promotions from Unicom and Telecom to get one month of server access and tokens).
However, I hadn’t tried it on macOS yet. The problem is I only have one MacBook Air, so a bare-metal deployment on this machine isn’t really an option. Then it occurred to me — Windows has virtual machines, so why not install a VM on the Mac and run macOS inside it? Easier said than done — and it turned out to be extremely simple, just clicking Next all the way through.

1. Install a Virtual Machine

1.1 Download UTM

For running a macOS virtual machine on a Mac, UTM is the go-to choice — no hesitation needed. Download: https://mac.getutm.app/
Note: Do NOT download UTM from the Mac App Store — the store version requires payment. The version from the official website is completely free and functionally identical.

Download

1.2 Install the OS

Once UTM is installed, create a new virtual machine in UTM, select a system image, and proceed with the installation.

utm-app

Port

Port

Port

The OS installation process won’t be covered in detail here — it’s straightforward, just click Next all the way through.

2. Initialize macOS

Setting up macOS inside the VM is the same as setting up a brand-new Mac for the first time — nothing special to explain here.

macOS initialized inside the VM

3. Prevent the MacBook Air from Sleeping and Turning Off the Screen

  1. Keep the MacBook Air plugged into its charger at all times. Don’t worry about damaging the battery — when plugged in, the battery isn’t in use. Go to System Settings → Battery → Battery Health → Enable Optimized Battery Charging. That said, do keep an eye on temperature: running too hot will shorten battery life. A cooling stand is recommended, and in summer, a small desk fan aimed at the machine helps.

  2. The MacBook Air will auto-sleep by default. To prevent this, go to Battery → Options → Enable “Prevent automatic sleeping when the display is off while connected to power adapter”. Also set Wake for network access → Always.

  3. Download Amphetamine from the App Store, and in its Quick Settings check Allow Display to Sleep.

  4. Turn the MacBook Air’s screen brightness all the way down, and let the MacBook keep running in the background.

Install OpenClaw

There are many installation guides available — please refer to other tutorials for the details. I won’t repeat them here.

  • 链接:

楼盘日照及噪音分析模拟

有如下功能:

3D 场景建模与布局

  • 拖拽式操作 :将预设模型拖入 3D 场景自由布局
  • 交互控制
    • 左键:选择/移动模型
    • 右键:旋转视角
    • 滚轮:缩放视图
  • 参数编辑 :右侧面板实时修改模型属性

☀️ 日照分析功能

  • 节气选择 :支持 24 节气(默认冬至 12 月 21 日)
  • 时间轴动画 :06:00–18:00 日照轨迹动态演示
  • 播放控制 :1x/2x/4x/8x 速度调节
  • 采样精度 :5/15/30/60 分钟间隔可选(精度与速度平衡)
  • 地理定位 :自动计算太阳高度角/方位角(基于 suncalc 算法)
  • 规范校验
    • 日照间距系数(默认 1.2)
    • 最低日照时长(≥2 小时)
    • 基准日设定(大寒日)
  • 每栋楼每一户 日照热力图
  • 室内光照进深计算
  • 经纬度任意设置

🔊 噪音模拟功能

  • 声源标定
    • 源强基准:dB(A)/m(按道路线源整体调节)
    • 建筑遮挡衰减:被建筑遮挡时的额外分贝扣减
    • 空气衰减:每 100 米传播的附加衰减
  • 默认参数 :源强 45 dB(A)/m|遮挡 18 dB|空气 0.6 dB/100m
  • 可视化反馈 :结合建筑布局评估不同户型的噪音暴露水平
  • 每户噪音计算 :能计算出每栋、每户的噪音数值

操作演示

视频链接
【买房怕采光差?噪音大?我做了个免费软件,算尽 24 节气日照!】

Goodbye PC: The Best Solution for Using an iPad (Tablet) Exclusively for Work, Study, and Entertainment

Author: OwnDing

Date: 2022-12-20

Back in March 2022, the battery on my Microsoft Surface Laptop — which I had been using for over three years — started to swell. Official repair costs were too high since the warranty had expired, and attempting a self-repair ran into the frustrating problem of stripped screws. All of this got me thinking about replacing the laptop. But then I thought: spending 7,000–8,000 RMB on a laptop that only lasts three years, and having to lug it around every day — it just didn’t seem worth it.

That’s when I remembered the iPad Pro’s famous tagline: “Your next computer is not a computer.” On impulse, I decided not to buy a laptop at all — I would use only the iPad Pro for work, study, and entertainment.

My day-to-day computer use is mainly document writing and software development. So I searched the App Store for suitable replacement apps, but nothing was satisfactory — even editing a complex Word document was a struggle, let alone writing code. I also looked at other people’s iPad/tablet productivity setups online, but they all had drawbacks: too expensive, or too inconvenient to use.

Then, at the end of March, I happened to come across a Spring Festival promotion from Tencent Lightweight Cloud: 4 cores, 8 GB RAM, 10 Mbps bandwidth, 100 GB storage — only 998 RMB for 3 years. I immediately decided to go with an iPad + cloud PC setup, treating the cloud PC as just another app.

image
iPad Pro connecting to a cloud PC via RD Client. Although the title says “goodbye PC,” what I’m really saying goodbye to is the physical computer in my hands — a cloud PC is still needed for complex work and study tasks. After using this setup for 9 months, I found it fully meets my needs for both productivity and entertainment, and most importantly, the cost is low. Even during extended business trips (about a week), there are no issues at all, and a tablet is so much easier to carry.

Without further ado — what do you need if you want to work and study using only an iPad or tablet?

An iPad or other tablet; a Bluetooth keyboard, mouse, and docking hub + a cloud PC (choose specs based on your needs, running Windows Server 2019). Yes, with just these items you can leave your bulky computer behind while still enjoying everything a tablet has to offer.

Tablet Selection

Both iPads and Android tablets can meet the needs of productivity and study. That said, a larger screen size is recommended.

Cloud Server Selection

Choose a cloud server provider based on your preference. It is recommended to buy a lightweight cloud server during major sale events such as Double 11, Double 12, or Chinese New Year, when discounts are the largest. For example, the Tencent Cloud Lighthouse server I purchased costs only 998 RMB for 3 years (Spring Festival promotion), and the 8 GB RAM configuration is more than enough for everyday office work.

You can also choose Tianyi Cloud PC, which offers larger bandwidth and is even suitable for watching movies on the cloud:

image
Tianyi Cloud PC pricing. If you buy a tablet for around 3,000 RMB and plan to use it for 3 years, the annual tablet cost is about 1,000 RMB; if you buy a cloud PC during a promotional period, the annual cost is around 600 RMB. That makes your total 3-year spend approximately 4,800 RMB — and you end up with both a capable computer and a tablet. Sounds like a great deal, right?

Security Recommendations (Important)

When connecting an iPad or other tablet to a cloud PC via Microsoft RD Client, the remote desktop port is exposed to the public internet, which inevitably introduces security risks. The following recommendations can help harden your cloud PC:

  1. Use a strong password. Set a strong password for your cloud server.

  2. Multi-factor authentication. Install the free version of Duo Security — remote login to the cloud PC will then require phone confirmation. Website: Multi-Factor Authentication & Single Sign-On

image
Phone-based second factor required at remote login.
image
Remote login authentication configured via Duo Security.
image
Authorizing login via the Duo mobile app. 3. Install IPBan (free). Exposing remote desktop ports to the internet makes the server vulnerable to brute-force attacks. IPBan automatically adds IP addresses with repeated failed login attempts to the firewall blocklist. Link: GitHub - DigitalRuby/IPBan: Since 2011, IPBan is the worlds most trusted, free security software to block hackers and botnets. With both Windows and Linux support, IPBan has your dedicated or cloud server protected. Upgrade to IPBan Pro today and get a discount. Learn more at ↓

image
IPBan GitHub homepage. The above three measures are foundational security recommendations. With these three in place, unauthorized logins to your cloud PC are extremely unlikely.

Other security hardening options — such as changing the remote desktop port or restricting login to specific IP addresses — are somewhat more complex for most users.

Setting Up an Online Development Environment (For Developers)

For developers or those learning to code, having your own server lets you set up an online development environment and write and debug code directly from the browser on an iPad or tablet.

  1. Frontend — Install Code-Server (free)

image
Online coding and debugging. 2. Backend — Install JetBrains Projector (free)

image
IDEA online coding and debugging. If any of these ports are exposed to the public internet, pay close attention to security. Exposing ports publicly is not recommended.

Summary

At the current stage, apps on iPads or Android tablets alone cannot meet the productivity needs of most people — but paired with a cloud PC, the story changes entirely. You can truly leave your physical computer behind and go anywhere with just a tablet, whether it’s a quick outing or a week-long business trip. In a pinch, you can also log into the cloud PC from your phone to handle urgent tasks.

image
RD Client mobile app — for emergency use on your phone. For anyone with mobile productivity needs, this setup is simply unbeatable ;)

I previously built a lightweight GB28181 platform, but installing it required some familiarity with containers, which made the experience a bit inconvenient. So I decided to package it as a double-click-to-run application for end users. To achieve this, ZLMediaKit needs to be compiled on Windows.
This document explains how to compile ZLMediaKit on Windows 11.
During compilation following the official tutorial, I encountered several errors and found some parts of the documentation unclear. I felt it was necessary to write a supplementary guide.
Please follow the steps one by one.

1. Prerequisites

Before starting the build, make sure the following software is installed in your development environment:

  • Visual Studio: VS2022 (with the Desktop development with C++ workload installed).
  • Git: For cloning the repository.

I performed the build on Windows 11 with VS2022. You do not need to open VS2022 during the build process — only PowerShell and the x64 Native Tools Command Prompt for VS 2022 are needed.

2. Get the Source Code

Open a command-line tool (CMD or PowerShell) and run the following commands to clone the repository and initialize submodules:

1
2
3
4
5
6
7
8
# Clone the main repository
git clone https://github.com/ZLMediaKit/ZLMediaKit.git

# Enter the directory
cd ZLMediaKit

# Initialize submodules (important — the build will fail without this)
git submodule update --init --recursive

The code I compiled is from the latest master branch as of 2026/3/1.


3. Windows Build Using scoop + vcpkg

Note: The following is based on the ZLMediaKit official documentation for Windows compilation, with some modifications I made to ensure a successful build.

The following describes one way to compile ZLMediaKit using scoop + vcpkg.

  • scoop: A command-line package manager for Windows
  • vcpkg: A C++ library manager initiated by Microsoft, containing a large number of commonly used open-source libraries

Since both tools are command-line based, they integrate very well into automated workflows. Highly recommended.

⚠️ Note

  • All operations below must be performed in a PowerShell terminal unless otherwise specified.

4. Install Build Dependencies via scoop and vcpkg

4.1 Download and Install scoop, Then Install Dependency Tools

Note: Simply run the commands below directly in PowerShell. Errors are rare in this step.

The following installs the dependency tools cmake and ninja (optional but recommended). Skip this step if they are already installed.

For full details, refer to the official documentation. The following lists only the relevant brief steps:

  1. Set the SCOOP environment variable to configure the installation directory for scoop and the packages it manages:

    1
    $env:SCOOP = 'C:\work\develop\scoop'
  2. Allow PowerShell script execution for the current user:

    1
    Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
  3. Install scoop:

    1
    iwr -useb get.scoop.sh | iex
  4. Add the extras bucket to scoop:

    1
    scoop bucket add extras
  5. Install cmake and ninja:

    1
    scoop install cmake ninja

💡 Tip: For convenience later, set C:\work\develop\scoop as the SCOOP environment variable and append C:\work\develop\scoop\shims to the PATH environment variable.

env

env

4.2 Download and Configure vcpkg, Then Install Dependency Libraries

The following installs the required dependency libraries, specifically: openssl and libsrtp. Other optional dependencies (e.g. ffmpeg) should also be installable, though they have not been tested yet.

For detailed vcpkg usage, refer to:

  1. Download vcpkg, which includes various configuration scripts and build scripts for open-source libraries. Assume the download path is C:\work\develop:

    1
    git clone https://github.com/microsoft/vcpkg
  2. Download the pre-built vcpkg package manager tool:

    1
    .\vcpkg\bootstrap-vcpkg.bat -disableMetrics
  3. Build openssl:

    1
    .\vcpkg\vcpkg.exe install --triplet=x64-windows-static openssl
  4. Build libsrtp (requires ENABLE_OPENSSL):

    Edit C:\work\develop\vcpkg\ports\libsrtp\portfile.cmake and update vcpkg_configure_cmake to the following: (Note: the configuration below has been updated to match the current version)

    1
    2
    3
    4
    5
    6
    7
    8
    vcpkg_cmake_configure(
    SOURCE_PATH "${SOURCE_PATH}"
    OPTIONS
    "-DCMAKE_PROJECT_INCLUDE=${CMAKE_CURRENT_LIST_DIR}/cmake-project-include.cmake"
    -DLIBSRTP_TEST_APPS=OFF
    -DENABLE_OPENSSL:BOOL=ON
    ${FEATURE_OPTIONS}
    )
    1. Then build (official method):

      1
      .\vcpkg\vcpkg.exe install --triplet=x64-windows-static libsrtp
    2. Or alternatively (the method I used later):

      1
      .\vcpkg\vcpkg.exe install "libsrtp[openssl]:x64-windows-static"

    Note: I successfully compiled the program using method 1, but later discovered a WebRTC issue. After investigation, it appeared to be a compatibility problem between OpenSSL and libsrtp. I had originally built libsrtp using the official method, and the issue was resolved only after rebuilding libsrtp with the command above.

    1
    2
    3
    # Uninstall first, then reinstall
    .\vcpkg\vcpkg.exe remove libsrtp:x64-windows-static --recurse
    .\vcpkg\vcpkg.exe install "libsrtp[openssl]:x64-windows-static"

5. Compile ZLMediaKit

Open the VS2022 developer command prompt from the Start Menu (x64 Native Tools Command Prompt for VS 2022). The PowerShell-based x64 version may not be available by default — you can start with the cmd version and then run powershell to switch to PowerShell.

tools

tools

5.1 Modify CMakeLists.txt

Search for OPENSSL_LIBRARIES in the file and replace the surrounding block with the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Check if openssl is installed
# find openssl installed
find_package(OpenSSL QUIET)
if(OPENSSL_FOUND AND ENABLE_OPENSSL)
message(STATUS "found library: ${OPENSSL_LIBRARIES}, ENABLE_OPENSSL defined")
include_directories(${OPENSSL_INCLUDE_DIR})
update_cached_list(MK_COMPILE_DEFINITIONS ENABLE_OPENSSL)
update_cached_list(MK_LINK_LIBRARIES ${OPENSSL_LIBRARIES})
if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND OPENSSL_USE_STATIC_LIBS)
update_cached_list(MK_LINK_LIBRARIES ${CMAKE_DL_LIBS})
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
# On Windows, OpenSSL (especially vcpkg static libs) depends on CryptoAPI
update_cached_list(MK_LINK_LIBRARIES Crypt32)
# WS2_32 is already included in the WIN32 branch below, so this is optional
# update_cached_list(MK_LINK_LIBRARIES ws2_32)
endif()
else()
set(ENABLE_OPENSSL OFF)
set(ENABLE_WEBRTC OFF)
message(WARNING "openssl not found; rtmp will not support flash player, and https/wss/rtsps/rtmps/webrtc will be disabled")
endif()

The key change is to replace the block with the following snippet — leave the rest untouched (the exact location may vary between ZLMediaKit versions, so pay attention to where you apply the change):

1
2
3
4
5
6
7
8
if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND OPENSSL_USE_STATIC_LIBS)
update_cached_list(MK_LINK_LIBRARIES ${CMAKE_DL_LIBS})
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
# On Windows, OpenSSL (especially vcpkg static libs) depends on CryptoAPI
update_cached_list(MK_LINK_LIBRARIES Crypt32)
# WS2_32 is already included in the WIN32 branch below, so this is optional
# update_cached_list(MK_LINK_LIBRARIES ws2_32)
endif()

5.2 Run the Build Commands

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Run the following commands from the ZLMediaKit source root directory.
# Make sure you have downloaded the ZLMediaKit source and run: git submodule update --init --recursive
mkdir build
cd build

$VCPKG_CMAKE = 'C:\work\develop\vcpkg\scripts\buildsystems\vcpkg.cmake'
$VCPKG_INSTALL_PATH = 'C:\work\develop\vcpkg\installed\x64-windows-static'

$CMAKE_OPTIONS = @(
"-GCodeBlocks - Ninja"
"-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo"
"-DCMAKE_C_COMPILER:STRING=cl.exe"
"-DCMAKE_CXX_COMPILER:STRING=cl.exe"
"-DCMAKE_TOOLCHAIN_FILE:FILEPATH=$VCPKG_CMAKE"
"-DCMAKE_PREFIX_PATH:FILEPATH=$VCPKG_INSTALL_PATH"
"-DVCPKG_TARGET_TRIPLET:STRING=x86-windows-static"
"-DENABLE_WEBRTC:BOOL=ON"
)

cmake .. @CMAKE_OPTIONS
cmake --build . --target all

After a successful build, a release directory will appear in the source root containing the compiled binaries.
Release

6. Running

Navigate to C:\work\develop\ZLMediaKit\release\windows\RelWithDebInfo and double-click MediaServer.exe to run it directly.

Run

You only need to copy MediaServer.exe, MediaServer.pdb, and the www directory to another location to use the basic functionality.

Release

7. Troubleshooting

Issue 1: WebRTC Shows an OpenSSL Error

Cause: A compatibility issue between OpenSSL and libsrtp. libsrtp needs to be rebuilt.

1
2
3
# Uninstall first, then reinstall
.\vcpkg\vcpkg.exe remove libsrtp:x64-windows-static --recurse
.\vcpkg\vcpkg.exe install "libsrtp[openssl]:x64-windows-static"

Overview

I hadn’t paid much attention to OpenClaw before, mainly because the API consumption is relatively high and costly. This time I received a free Unicom Coding Plan Pro along with a 2-core 4GB cloud server, so I decided to give it a try.
This article first covers how to install OpenClaw on an Ubuntu cloud server. Usage guides and further details will be written when time permits.

  1. OS: Ubuntu 22.04 Server
  2. OpenClaw version: 2026.2.26
  3. Cloud server: 2-core 4GB RAM
  4. User: root

Installation

Install OpenClaw

I am using a cloud server with a clean OS — no software pre-installed.
Installing OpenClaw is actually very simple. Run the following one-liner to install it:

1
curl -fsSL https://openclaw.ai/install.sh | bash

The installation script will automatically install Node, OpenClaw, and other dependencies. Select “Yes” for all prompts in the interface.

After installation, the Gateway will fail to start (don’t worry — once we complete the configuration below, we just need to restart the Gateway). At the end, the following information will appear on the screen:

1
2
3
4
5
6
7
8
9
10
11
12
🦞 OpenClaw 2026.2.26 (bc50708) — Your task has been queued; your dignity has been deprecated.

Dashboard URL: http://127.0.0.1:18789/#token=85xxxxxxxxxxxxd9c6b036328fe00d04fd3c98
Copy to clipboard unavailable.
No GUI detected. Open from your computer:
ssh -N -L 18789:127.0.0.1:18789 root@192.168.0.167
Then open:
http://localhost:18789/
http://localhost:18789/#token=85xxxxxxxxxxxxd9c6b036328fe00d04fd3c98
Docs:
https://docs.openclaw.ai/gateway/remote
https://docs.openclaw.ai/web/control-ui

At this point, you cannot access http://localhost:18789/#token=85xxxxxxxxxxxxd9c6b036328fe00d04fd3c98 normally.

No worries — just follow the configuration steps below.

Installation screen 1

Installation screen 2

Install Nginx (Skip this step if you are only using it locally with a GUI)

Run the following command:

1
apt install -y nginx

If a selection prompt appears, simply confirm and proceed.

Navigate to /etc/nginx/, find the nginx.conf file, and update it as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
worker_connections 768;
# multi_accept on;
}

http {

##
# Basic Settings
##

sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
server_tokens off;

# server_names_hash_bucket_size 64;
# server_name_in_redirect off;

include /etc/nginx/mime.types;
default_type application/octet-stream;

##
# SSL Settings
##

ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;

##
# Logging Settings
##

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

##
# Gzip Settings
##

gzip on;

# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

##
# Virtual Host Configs
##

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

server {
listen 18790;
server_name your-domain.com; # Replace with your domain name or IP

location / {
proxy_pass http://127.0.0.1:18789;

# Required header forwarding
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# WebSocket support (if OpenClaw uses WS)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

# Timeout and buffer optimization (optional)
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}

# Health check endpoint (optional)
location /health {
access_log off;
proxy_pass http://127.0.0.1:18789/health;
}
}
}

Save the file and run the following command:

1
nginx -s reload

Start the Gateway

Run the following commands:

1
2
openclaw config set gateway.mode local
openclaw gateway restart

local

If the console shows no failure messages, the Gateway has started successfully. After configuring the firewall, you can access the UI in your browser, for example: http://:18790/#token=85xxxxxxxxxxxxd9c6b036328fe00d04fd3c98

At this point the UI may still show some errors — proceed to the next step.

Configure OpenClaw

Once you can access the UI, it is still not usable yet — you need to modify the OpenClaw configuration file located in the /root/.openclaw directory.

Below I provide the complete configuration that you can use directly. Replace the token, allowedOrigins, apiKey, and other values with your own settings. I am using the free Unicom Coding Plan.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
{
"meta": {
"lastTouchedVersion": "2026.2.26",
"lastTouchedAt": "2026-02-28T13:04:18.321Z"
},
"wizard": {
"lastRunAt": "2026-02-28T11:48:10.150Z",
"lastRunVersion": "2026.2.26",
"lastRunCommand": "doctor",
"lastRunMode": "local"
},
"agents": {
"defaults": {
"compaction": {
"mode": "safeguard"
},
"maxConcurrent": 4,
"subagents": {
"maxConcurrent": 8
},
"model": {
"primary": "Unicom/MiniMax-M2.5"
},
"models": {
"Unicom/MiniMax-M2.5": {}
}
}
},
"messages": {
"ackReactionScope": "group-mentions"
},
"commands": {
"native": "auto",
"nativeSkills": "auto",
"restart": true,
"ownerDisplay": "raw"
},
"gateway": {
"mode": "local",
"auth": {
"mode": "token",
"token": "Keep the original Token"
},
"controlUi": {
"allowedOrigins": [
"http://60.13.54.190:18790",
"http://192.168.0.167:18790",
"http://192.168.0.167:18789",
"http://127.0.0.1:18789"
],
"allowInsecureAuth": true,
"dangerouslyDisableDeviceAuth": true
}
},
"models": {
"mode": "merge",
"providers": {
"Unicom": {
"baseUrl": "https://aigw-gzgy2.cucloud.cn:8443/v1",
"apiKey": "sk-sp-xxxxxxxxxxxxxxxxxxxxxxxxxxx",
"api": "openai-completions",
"models": [
{
"id": "MiniMax-M2.5",
"name": "MiniMax-M2.5",
"reasoning": false,
"input": ["text"],
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"contextWindow": 128000,
"maxTokens": 32000
},
{
"id": "Qwen3.5-397B-A17B",
"name": "Qwen3.5-397B-A17B",
"reasoning": false,
"input": ["text"],
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"contextWindow": 128000,
"maxTokens": 32000
}
]
}
}
}
}

After making your edits, first back up the original openclaw.json file, then replace it with the updated file and restart the Gateway:

1
openclaw gateway restart

Once started successfully, you can access the UI in your browser, for example: http://:18790/#token=85xxxxxxxxxxxxd9c6b036328fe00d04fd3c98

Everything should now be working correctly in the UI!

UI

Troubleshooting

Issue 1: Gateway start blocked: set gateway.mode=local (current: unset) or pass –allow-unconfigured

Solution:

1
2
openclaw config set gateway.mode local
openclaw gateway restart

Issue 2: origin not allowed (open the Control UI from the gateway host or allow it in gateway.controlUi.allowedOrigins)

Solution:
Modify the "gateway" section in openclaw.json, add the "controlUi" block, and restart the Gateway:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
"gateway": {
"mode": "local",
"auth": {
"mode": "token",
"token": "85xxxxxxxxd95d0d9c6b0xxxxxxxx04fd3c98"
},
"controlUi": {
"allowedOrigins": [
"http://60.13.54.190:18790",
"http://192.168.0.167:18790",
"http://192.168.0.167:18789",
"http://127.0.0.1:18789"
],
"allowInsecureAuth": true,
"dangerouslyDisableDeviceAuth": true
}
}

浙江联通宁波用户, 冰激凌129套餐,这个套餐常年7折,所以我每月是90块话费。
这90块话费包含了 1000M联通宽带,以及 IPTV 费用,这两样都没另外收钱。

下面介绍下免 副卡10元月租的方法:

1、首先我先找 之前联通的客服(一般是企业微信添加,营业厅人员,说是你的专属客服),平常都有一些优惠活动

2、我微信询问 我想办一张副卡,但是有10块月租,我想免费使用副卡,有什么办法可以实现

3、客服说让我先办副卡,办好后,找她。 她可以做一个活动取消副卡的费用

4、我就在联通App 上办理了张副卡,这张副卡首月免月租的

5、副卡办理很快,有专门人员上门办理,服务挺好,几分钟就办好了

6、办好后,我就找之前的客服,说我副卡办好了,需要取消月租。客服让我把卡号发她,帮我处理

7、就这样,我的副卡没有月租费用了

截图

国内订阅 ChatGPT 或 Gemini 其实有些麻烦,Gemini 还好,只要是 Visa 或 Mastercard 就能订阅,但是 ChatGPT 限制有点多。

之前折腾过虚拟信用卡,不过这些虚拟卡免不了要跑路或倒闭,最后还是要自己解决正常充值的问题。

国内的银联卡其实也能订阅 ChatGPT ,不过需要将卡绑定到 Google PayApple Pay,然后通过他们在手机上进行支付。这种方法我已经稳定使用了 1年了,完全没有出现问题。

我的信用卡是 交通银行 MasterCard 双币信用卡,卡号是52开头。

我是将 信用卡绑定到 Google Pay,地址填的美国免税州的地址,在安卓手机上进行订阅,每次都是 19.9美元 原价。


手机支付
手机支付


支付成功截图
手机支付成功


自动订阅
自动订阅


如果只是想使用API,推荐 微软 Azure,国内卡随便申请;亚马逊的平台可以提供 Claude API。两个都可以用国内卡支付,不过API比较费钱。

在昨天之前我还不会用 AI 制作长视频,只会给AI提示词,然后它生成一个牛头不对马嘴德10秒视频,没法看。

因为需要给自己的产品做宣传视频,我了解了下 如何使用AI做长视频,不过还是没学会。

最后,了解到 Google flow ,薅了一个月羊毛准备自己上手试试。

特别说明 我做这个视频之前,没有任何 AI 生成视频的经验,所以 我的步骤对于 刚想入门的仁应该有很大的借鉴意义。

全程 AI 辅助,我甚至把 我跟 AI 的对话 完整截取了下来,照着来准能完成长视频。一图胜千言。

工具

  • Google Gemini
  • Google flow

思路

1、让 AI 描绘出视频的场景
2、让 AI 生成 关键场景的 图片。 我上手时,总共6个场景,每个场景 AI 都给出了标志性的 图片
3、让 AI 提供 每个场景 生成视频 的提示词,我有6个场景,所以会有6段提示词
4、在 Google flow 里,上传我们的 标志场景图片
5、场景选择技巧。 比如 开始 选 场景1 图片,结束 选 场景1 图片,提供 场景1 的提示词,那么 Google flow 就会针对 场景1 生成 10秒左右的动画,然后 我们 开始 选 场景1 的图片,结束 选 场景2 的图片,提供 场景1 的提示词 ,那么 Google flow 会生成从场景1 到 场景2 的过渡视频。我们把这两端视频结合起来,就能比较好的提供场景1的动画以及场景1到场景2的过度动画,衔接非常自然。
6、一次类推, 场景2–>场景2,场景2–>场景3 …

是不是很简单 ? ;)

AI 聊天记录

下面直接提供 我跟 AI 的聊天记录,描述了一个新手怎么使用 AI 完成 长视频创作。

场景图片


场景提示词

视频场景提示词

AI制作视频

制作视频用的 Google flow

1、新建项目
2、上传 场景图片
3、根据图片制作视频(见 思路 第5点)

创建项目

flow创建项目

在项目里添加 图片,以及创建视频

flow创建视频

在项目里对 比较满意的视频 加入到 场景 中

flow场景

视频链接

【AI生成的长视频演示】 https://www.bilibili.com/video/BV1JgXpB8E45/?share_source=copy_web&vd_source=9550a012bf30d7adb10982a6864c651c

0%