Wiki
Other Operations
Existing English translations were reused. 21 current source blocks remain in Simplified Chinese, without triggering paid translation.
1.How does an industrial PC connect to Wi-Fi?
1.1.现在无法进入ssh
When we move an industrial PC from one environment to another, and we have never connected to the Wi-Fi in the new environment, how can we get the industrial PC online without a screen?
Enter the hard disk directory of the industrial PC, enter/etc/netplan/; under it there are many yamls, find the one that best matches the format below:
network:
version: 2
wifis:
NM-6f414fe0-2658-48ff-89ee-c7981b87bc96:
renderer: NetworkManager
match:
name: "wlan0"
dhcp4: true
dhcp6: true
access-points:
"EMIS_Vinci_Robocon_5G":
auth:
key-management: "psk"
password: "vinci666"
networkmanager:
uuid: "6f414fe0-2658-48ff-89ee-c7981b87bc96"
name: "EMIS_Vinci_Robocon_5G"
passthrough:
wifi-security.auth-alg: "open"
ipv6.addr-gen-mode: "default"
ipv6.ip6-privacy: "-1"
proxy._: ""
networkmanager:
uuid: "6f414fe0-2658-48ff-89ee-c7981b87bc96"
name: "EMIS_Vinci_Robocon_5G"
Change it to the new Wi-Fi name and password:
network:
version: 2
wifis:
wlan0:
dhcp4: true
dhcp6: true
access-points:
"EMIS_Vinci_Robocon_5G":
password: "vinci666"
The industrial PC can connect to the network as soon as it is powered on.
1.2.现在可以ssh
查网卡:
nmcli device status

当前连接的Wifi:
nmcli device wifi list

查询当前周围有什么wifi
sudo nmcli device wifi list --rescan yes

连接wifi:
sudo nmcli --ask device wifi connect "新的WiFi名称"

2.SSH remote development
2.1.Environment Preparation
1. Hardware Preparation
First, there must be an industrial computer (X86 small computer, professional industrial computer, Raspberry Pi, etc.).
The hardware carriers of control systems are diverse, commonly based on ARM, x86, and other architectures, such as PCs, industrial computers, Raspberry Pi, NVIDIA Jetson, etc. Different processors have their own advantages and disadvantages: PCs and industrial computers offer powerful processor performance but have high power consumption, large size, and poor flexibility, while embedded systems are the opposite. For us, we can independently select an appropriate control system based on various factors such as the robot platform's electrical requirements, load capacity, space, and purpose.
Regardless of which processor is chosen, as long as robot development is to be carried out and ROS or ROS2 is installed, then for developers, there is no essential difference in usage; or in other words, as a software engineer, in some scenarios there is no need to focus on hardware selection.
2. Set a static IP
When connecting remotely, regardless of the tool used, you need to locate the host being connected to based on its IP address, and then log in to that host using an account and password. Therefore, we need to obtain the IP address first. Moreover, since the IP is required for every connection, to ensure convenience and stability of the connection, it is best to set the IP address of the host being connected to as a static IP. The specific steps are as follows.
1. Enter the settings interface
Start the connected host (a monitor or HDMI capture card is required for startup, and after configuring SSH remote access, the monitor or HDMI capture card is no longer needed), and enter the settings interface.

2. Configure the connected network

3. Set a static IP
View the current IP address.

Set a static IP.

At this point, the IP configuration is complete.
2.2.Environment Setup
Concept
SSH (Secure Shell) is a versatile, powerful, software-based network security solution. Every time a computer sends data to the network, SSH automatically encrypts it. When the data reaches its destination, SSH automatically decrypts the encrypted data. The entire process is transparent, and using OpenSSH tools will enhance your system's security. SSH is easy to install and simple to use.
Implementation
The SSH implementation architecture is divided into two major parts: the client and the server. The client is the sender of data, and the server is the receiver of data. In the current scenario, we need to send data from the local host to the remote host. Therefore, the local host needs to install and start the SSH client, while the remote host needs to install and start the SSH server. The specific overall implementation process is as follows:
-
Install an SSH client on the local host and an SSH server on the remote host;
-
Start the SSH service on the remote host;
-
Log in to the remote host from the local host;
-
Implement data transmission.
1. Install the SSH client and server
By default, the Ubuntu system already has the SSH client installed, so you only need to install the SSH server on the remote host. The installation command is as follows:
sudo apt install openssh-server
If the SSH client needs to be installed separately, run the following command:
sudo apt install openssh-client
2. Start the SSH service on the remote host
The command to start the SSH service on the remote host is as follows:
sudo /etc/init.d/ssh start
After startup, you can use the following command to check whether the service is running properly:
ps -e | grep ssh
If the startup is successful, the sshd program will be included.
In the future, frequent SSH remote logins will be needed. To simplify implementation, you can set the SSH service on the remote host to start automatically on boot. The command is as follows:
sudo systemctl enable ssh
3. Local remote login
To log in to the remote host, you can invoke the following command:
ssh -X 用户名@ip地址
Then, following the prompts, enter the login password to successfully log in.
To exit, you can call the exit command:
exit
4. Implement data transmission
Through SSH, on the local host, simply invoking the relevant command enables convenient data upload to or download from a remote host. The command format is as follows:
The format of the upload file instruction is as follows:
scp 本地文件路径 账号@ip:路径
The command format for uploading a folder is as follows:
scp -r 本地文件夹路径 账号@ip:路径
The download file command format is as follows:
scp 账号@ip:路径 本地文件夹路径
The format of the download folder instruction is as follows:
scp -r 账号@ip:路径 本地文件夹路径
Optimization
Every time you log in remotely, you need to enter a password, which is inconvenient. You can use keys to simplify the login process, achieve passwordless login, and improve operational efficiency. The implementation idea is: generate a pair of public and private keys, store the private key locally, and upload the public key to the server. Each time you log in, the local machine directly uploads the private key to the server. If the server has a matching public key, it considers the user legitimate and directly creates an SSH connection. The specific implementation steps are only two:
-
Generate a key pair locally;
-
upload the public key to the remote host.
1. Generate a key pair
Generate a public-private key pair on the local client: (press Enter for each prompt to accept the defaults)
ssh-keygen
The above command will create a public-private key pair in the .ssh folder under the user directory:
-
id_rsa (private key);
-
id_rsa.pub (public key).
2. Public key upload
The upload instruction is as follows:
ssh-copy-id -i ~/.ssh/id_rsa.pub 账号@ip
The above command uploads the local public key to the ssh directory on the remote host, where the file authorized_keys stores the public key content.
In the future, there will be no need to enter a password when logging in remotely.
2.3.Optimizing with VSCode
In the previous section, we introduced the use of SSH for remote connections, but using SSH alone also has some shortcomings. For example, when editing file contents, you need to use the vi editor, and within a single terminal, you cannot edit multiple files at the same time. In this section, we will introduce a more practical feature—using VSCode with plugins to achieve remote development. This allows us to perform remote development in a graphical way, making it more convenient and efficient than using SSH, and it can greatly improve programming development efficiency.
1. Preparation
VS Code remote development relies on SSH; please first configure an SSH remote connection according to the previous section.
2. Install the Remote Development extension for VSCode
Launch VSCode, first click the Extensions button in the sidebar, then in the search bar of扩展:商店enterRemote Developmentand click the plugin with the same name, and finally in the display area on the right click安装.

3. Configure remote connection
Step 1: Use the shortcut keyctrl + shift + pto open the command input window, and enterRemote-SSH:Connect to Host...; from the pop-up list, select the option with the same name.

Step 2: After Step 1 is completed, a new command window will pop up as shown below. Select from the drop-down list Add New SSH Host.

Step 3: After Step 2 is completed, a new command window will pop up. In it, enter:ssh -X ubuntu@192.168.43.164,where ubuntu needs to be replaced with your login username, and 192.18.43.164 is replaced with the IP address of the host to be remotely connected.

Step 4: Select the first option in the pop-up list after completing Step 3 (or press Enter directly) to complete the configuration. After successful configuration, a prompt message will be displayed.


4. Use
Step 1: Continue using the shortcut keyctrl + shift + pOpen the command input window and enterRemote-SSH:Connect to Host...At this point, the IP address configured in step 3 will be displayed in the list. Select it directly, and after selection, VSCode will open a new window.

Alternatively, you can click the sidebar's远程资源管理器, select the server to connect to from the pop-up server list, right-click it, and choose to establish a remote connection in the current window or a new window.

步骤2:选择菜单栏的文件下的打开文件夹,在弹窗列表中选择需要打开的文件夹并点击确定即可。

Ultimately, we can then achieve remote development just like working with local files.
2.4.Advanced
2.4.1.Use hostname for SSH
When a device's IP keeps changing, you can use the hostname to connect.
First, you can check what the hostname of the device you want to develop remotely is?
hostname
For example, the output hostnameisDell-G15-5511
Then install on this deviceavahi-daemon:
sudo apt install avahi-daemon
sudo systemctl enable --now avahi-daemon
Then you can try it on a computer on the same local network:
ping Dell-G15-5511.local

If it can be pinged successfully, that is sufficient.
Then in the future, SSH can
ssh 用户名@Dell-G15-5511.local
3.Remote Desktop
Because X11 forwarding is far too inefficient, it is still necessary to use remote desktop access to view Rviz2, Gazebo, and so on (if needed).
We choose to use VNC to view it.
- Install VNC server:
Here, TigerVNC is used as an example for installation:
sudo apt install tigervnc-standalone-server tigervnc-common
- Set VNC password:
To set a password for a VNC user, run the following command:
vncpasswd
- Configure the VNC startup script:
Create a VNC configuration file, and create a startup file in the .vnc folder within the user's home directory:
mkdir -p ~/.vnc
nano ~/.vnc/xstartup
Enter the following content in the opened editor (using GNOME as an example):
#!/bin/sh
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
gnome-session
Save and exit (in nano, press Ctrl + O to save, then press Ctrl + X to exit).
- Grant execute permission:
Set execute permissions for the xstartup file:
chmod +x ~/.vnc/xstartup
- Start the VNC server:
vncserver -geometry 1920x1080 -localhost=0
The geometry option specifies the window size, and the localhost option is set to 0 to open connections. (Setting it to 1 allows only local connections.)
You will see output similar to :1, which indicates the display number of the VNC session. For example, if the output is :1, the port VNC listens on is 5901 (5900 + display number).
- View the VNC servers that have been started:
vncserver -list

- Connect to the VNC server:
Use a VNC client (such as vncviewer) to connect to the VNC server and enter your server IP and port. For example, if the server IP is 192.168.31.10 and the display number is 1, you should connect to 192.168.31.10:1, or directly enter 192.168.31.10:5901.
- Stop the VNC server:
If you need to stop the VNC server, you can use the following command:
vncserver -kill :1
Replace :1 with the actual display number you are using.


4.Switch graphical interface
You can first look at the current default mode:
systemctl get-default
If it isgraphical.targetit is graphical mode; if it ismulti-user.targetit is command-line mode.
Turn off the graphical interface (set to command-line mode):
sudo systemctl isolate multi-user.target
Disable the graphical interface by default (boot into command-line mode by default):
sudo systemctl set-default multi-user.target
Restart
sudo reboot
5.USB device name persistence
5.1.USB port settings
In Linux, after a USB serial device is plugged in or unplugged, the device node assigned by the system may change, for example:
/dev/ttyUSB0
/dev/ttyUSB1
/dev/ttyACM0
/dev/ttyACM1
If a program, ROS node, or startup script directly hardcodes /dev/ttyUSB0, when a device is unplugged and replugged, a new USB device is added, or the system boot order changes, the port number may change.
Therefore, in scenarios such as robots, unmanned vehicles, and embedded devices, it is generally necessary to establish astable device path or fixed aliasfor USB devices.
Common approaches mainly include:
- Using the automatically generated by Linux
/dev/serial/by-id/; - Using the automatically generated by Linux
/dev/serial/by-path/; - According to the device's
idVendor、idProduct、serialand other attributes, write udev rules; - Write udev rules based on the physical location of the host USB interface;
- For devices such as cameras, use
/dev/v4l/by-id/or/dev/v4l/by-path/.
5.1.1.First, configure serial port permissions.
Under Linux, a regular user may not have access permission to serial devices by default, so first add the current user to the dialout user group.
#### 将当前用户加入 dialout 用户组
sudo usermod -aG dialout $USER
#### 临时在当前终端加载新的用户组
newgrp dialout
#### 查看当前用户组中是否存在 dialout
groups
If the output includes:
dialout
Indicates that the current terminal already has serial port access permission.
Alternatively, log off the current desktop session and log back in so that the user group permissions take effect throughout the entire user session.
5.2.Prioritize the use of built-in fixed device paths in Linux.
Before writing your own udev rules, it is recommended to first check whether the system has already generated a stable symbolic link for the device.
For USB serial port devices:
ls -l /dev/serial/by-id/
ls -l /dev/serial/by-path/
For example:
usb-1a86_USB_Serial-if00-port0 -> ../../ttyUSB0
usb-STMicroelectronics_STM32_Virtual_ComPort_123456-if00 -> ../../ttyACM0
Among them:
/dev/serial/by-id/: mainly generated based on the device's own identity information;/dev/serial/by-path/: mainly generated based on the USB physical path through which the device is connected to the host.
5.2.1.Use /dev/serial/by-id/

If a device has a stable and unique serial number, it is usually preferred to use:
/dev/serial/by-id/xxx
For example:
/dev/serial/by-id/usb-STMicroelectronics_STM32_Virtual_ComPort_123456-if00
Even if the corresponding device node is from:
/dev/ttyACM0
becomes:
/dev/ttyACM2
by-id The path usually still remains unchanged.
Therefore, in the ROS 2 parameter, you can directly write:
port: /dev/serial/by-id/usb-STMicroelectronics_STM32_Virtual_ComPort_123456-if00
The greatest advantage of this approach is:
- Does not depend on
ttyUSBnorttyACMnnumbering; - After a USB device is moved to another port, it can generally still be recognized;
- It is very stable for devices with unique serial numbers;
- No need to write your own udev rules.
5.2.2.Use /dev/serial/by-path/

If the device does not have a unique serial number, or if the system cannot distinguish multiple identical devices through the device itself, you can use:
/dev/serial/by-path/
View:
ls -l /dev/serial/by-path/
For example:
pci-0000:00:14.0-usb-0:3:1.0-port0 -> ../../ttyUSB0
pci-0000:00:14.0-usb-0:4:1.0-port0 -> ../../ttyUSB1
This approach is actually based on:
Which USB port on the host is the device plugged into?
to distinguish devices.
For example, an autonomous vehicle has two completely identical radars:
前雷达 -> 固定插在 USB 口 A
后雷达 -> 固定插在 USB 口 B
At this point, two different by-path paths can be used directly in the program.
The disadvantages are:
If the USB ports are swapped, the corresponding logical identities of the devices will also change.
5.3.View USB device information
5.3.1.Use lsusb
After connecting a USB device, you can first execute:
lsusb
For example:
Bus 001 Device 007: ID 1a86:7523 QinHeng Electronics CH340 serial converter
Among them:
1a86:7523
Respectively correspond to:
idVendor = 1a86
idProduct = 7523
Note:
idVendor + idProductIt can only represent a certain class of USB products and usually cannot uniquely identify a specific device.
For example, two completely identical CH340 chips:
CH340 A -> 1a86:7523
CH340 B -> 1a86:7523
Their idVendor and idProduct are completely identical.
Therefore:
- Different device models can be distinguished by
idVendor + idProduct; - Multiple devices of the same model cannot be distinguished solely by
idVendor + idProduct.
5.3.2.View full device attributes
For serial port devices, you can use:
udevadm info --query=property --name=/dev/ttyACM0
Or:
udevadm info --query=property --name=/dev/ttyUSB0
Show only frequently used information:
udevadm info --query=property --name=/dev/ttyACM0 \
| grep -E 'ID_(VENDOR_ID|MODEL_ID|SERIAL|SERIAL_SHORT|PATH|USB_INTERFACE_NUM)'
Common outputs:
ID_VENDOR_ID=0483
ID_MODEL_ID=5740
ID_SERIAL=STMicroelectronics_STM32_Virtual_ComPort_123456
ID_SERIAL_SHORT=123456
ID_PATH=pci-0000:00:14.0-usb-0:3:1.0
ID_USB_INTERFACE_NUM=00
Common attribute descriptions:
| Attribute | Meaning |
|---|---|
ID_VENDOR_ID |
USB Vendor ID |
ID_MODEL_ID |
USB Product ID |
ID_SERIAL |
Complete device serial information |
ID_SERIAL_SHORT |
USB device serial number |
ID_PATH |
Physical path of the device connected to the host |
ID_USB_INTERFACE_NUM |
USB Interface number |
5.3.3.View udev matchable attributes
If you need to write your own udev rules, you can use:
udevadm info -a -p $(udevadm info -q path -n /dev/ttyACM0)
Or:
udevadm info -a -p $(udevadm info -q path -n /dev/ttyUSB0)
Alternatively, you can use:
udevadm info --attribute-walk --name=/dev/ttyUSB0
For example, view only KERNELS:
udevadm info --attribute-walk --name=/dev/ttyUSB0 | grep KERNELS
This information can be used to write custom udev rules.
5.4.Bind the port according to the USB device model
5.4.1.Requirements
In an Ubuntu system, a radar and a smart car are connected. The two devices are of different models, and fixed aliases are desired to be established for them.
For example:
雷达 -> /dev/mylidar
小车 -> /dev/mycar
5.4.2.Find idVendor and idProduct
Call:
lsusb
Assume we obtain:
雷达:10c4:ea60
小车:1a86:7523
Among them:
10c4 -> idVendor
ea60 -> idProduct
1a86 -> idVendor
7523 -> idProduct
5.4.3.Writing udev rules
At:
/etc/udev/rules.d/
Create a rule file in the directory, for example:
sudo vim /etc/udev/rules.d/99-usb-serial.rules
Input:
KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE:="0777", SYMLINK+="mylidar"
KERNEL=="ttyUSB*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0777", SYMLINK+="mycar"
Among them:
KERNEL: Match the device name assigned by the Linux kernel;ATTRS{idVendor}: USB vendor ID;ATTRS{idProduct}: USB product ID;MODE:="0777": Set device node permissions;SYMLINK+="xxx": Create a fixed symbolic link for the device.
For example:
/dev/mylidar -> /dev/ttyUSB0
/dev/mycar -> /dev/ttyUSB1
5.4.4.Make the rule take effect
Both Ubuntu and Fedora can uniformly use:
sudo udevadm control --reload-rules
sudo udevadm trigger
Then, unplug and reinsert the USB device.
It can also trigger only the tty subsystem:
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=tty
5.4.5.Test
ls -l /dev/mylidar
ls -l /dev/mycar
Or:
readlink -f /dev/mylidar
readlink -f /dev/mycar
May obtain:
/dev/ttyUSB0
/dev/ttyUSB1
5.4.6.Disadvantages
This method is only suitable for:
Devices of different USB models.
If two devices of exactly the same model are connected:
CH340 A -> 1a86:7523
CH340 B -> 1a86:7523
Then both devices will match the same udev rule.
Therefore:
KERNEL=="ttyUSB*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="mycar"
Cannot reliably distinguish between two identical USB devices.
At this point, it is necessary to continue using:
- USB Serial Number;
/dev/serial/by-id/;/dev/serial/by-path/;- Host USB physical interface.
5.5.Bind the port based on the device Serial Number
If multiple devices are the same model but each device has a different USB serial number, then this is the most recommended custom udev binding method.
For example:
设备 A:
idVendor = 1a86
idProduct = 55d4
serial = 0001
设备 B:
idVendor = 1a86
idProduct = 55d4
serial = 0002
You can write:
KERNEL=="ttyACM*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4", ATTRS{serial}=="0001", MODE:="0777", SYMLINK+="ttyACM_Lidar"
KERNEL=="ttyACM*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4", ATTRS{serial}=="0002", MODE:="0777", SYMLINK+="ttyACM_MCU"
Like so:
/dev/ttyACM_Lidar
/dev/ttyACM_MCU
then it can stably correspond to two devices.
Even if:
/dev/ttyACM0
/dev/ttyACM1
the numbering is swapped, the two fixed aliases can still point to the correct devices.
5.5.1.Recommended Inspection Method
udevadm info --query=property --name=/dev/ttyACM0 | grep SERIAL
For example:
ID_SERIAL=STMicroelectronics_STM32_Virtual_ComPort_123456
ID_SERIAL_SHORT=123456
If ID_SERIAL_SHORT is unique, it is very suitable as a device identifier.
5.6.Bind ports according to the host's physical USB interfaces
5.6.1.Requirements
Two radars of exactly the same model are installed on the unmanned vehicle, one at the front and one at the rear.
Two radars:
idVendorsame;idProductsame;- No unique Serial Number.
At this point, it can be distinguished based on the location of the host's USB interface.
5.6.2.Method 1: Directly use /dev/serial/by-path/
First, execute:
ls -l /dev/serial/by-path/
For example:
pci-0000:00:14.0-usb-0:3:1.0-port0 -> ../../ttyUSB0
pci-0000:00:14.0-usb-0:4:1.0-port0 -> ../../ttyUSB1
It can be stipulated:
USB 口 0:3 -> 前雷达
USB 口 0:4 -> 后雷达
Program direct use:
/dev/serial/by-path/pci-0000:00:14.0-usb-0:3:1.0-port0
/dev/serial/by-path/pci-0000:00:14.0-usb-0:4:1.0-port0
即可。
5.6.3.方法二:根据 KERNELS 创建自定义别名
View the first device:
udevadm info --attribute-walk --name=/dev/ttyUSB0 | grep KERNELS
View the second device:
udevadm info --attribute-walk --name=/dev/ttyUSB1 | grep KERNELS
Assumption correspondence:
第一台:
KERNELS=="1-1.3:1.0"
第二台:
KERNELS=="1-1.4:1.0"
Then you can create:
sudo vim /etc/udev/rules.d/99-lidar.rules
Write:
KERNEL=="ttyUSB*", KERNELS=="1-1.3:1.0", MODE:="0777", SYMLINK+="rplidar_front"
KERNEL=="ttyUSB*", KERNELS=="1-1.4:1.0", MODE:="0777", SYMLINK+="rplidar_back"
Reload:
sudo udevadm control --reload-rules
sudo udevadm trigger
After re-plugging:
ls -l /dev/rplidar_front
ls -l /dev/rplidar_back
5.6.4.Disadvantages
This method binds:
Host USB interface
rather than:
The USB device itself
Therefore, the device must be plugged into a fixed USB port.
If the front and rear radars swap interfaces:
前雷达插到后雷达 USB 口
Then the system will still identify the interface as:
/dev/rplidar_back
5.7.According to ID_PATH bind port
Similar to using KERNELS, rules can also be established based on ID_PATH.
View:
udevadm info --query=property --name=/dev/ttyUSB0 | grep ID_PATH
For example:
ID_PATH=pci-0000:00:14.0-usb-0:3:1.0
You can write:
SUBSYSTEM=="tty", ENV{ID_PATH}=="pci-0000:00:14.0-usb-0:3:1.0", MODE:="0777", SYMLINK+="rplidar_front"
Another interface:
SUBSYSTEM=="tty", ENV{ID_PATH}=="pci-0000:00:14.0-usb-0:4:1.0", MODE:="0777", SYMLINK+="rplidar_back"
Compared with writing KERNELS directly, this approach is usually more intuitive.
5.8.Composite multiple attribute binding ports
In practical engineering, multiple attributes can be matched simultaneously.
For example:
KERNEL=="ttyACM*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4", ATTRS{serial}=="0001", MODE:="0777", SYMLINK+="ttyACM_Lidar"
KERNEL=="ttyACM*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4", ATTRS{serial}=="0002", MODE:="0777", SYMLINK+="ttyACM_MCU"
KERNEL=="ttyUSB*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0777", SYMLINK+="ttyUSB_IMU"
Alternatively, you can use:
SUBSYSTEM=="tty", ENV{ID_VENDOR_ID}=="0483", ENV{ID_MODEL_ID}=="5740", ENV{ID_SERIAL_SHORT}=="12345678", MODE:="0777", SYMLINK+="ysu_mcu"
Finally, we get:
/dev/ysu_mcu
This approach is very suitable for robotics projects.
5.9.It is recommended to use a unified business device name
For robotics projects, it is not recommended that ROS 2 nodes be used directly:
/dev/ttyUSB0
/dev/ttyACM0
Business names can be established uniformly, for example:
/dev/ysu_mcu
/dev/ysu_gimbal
/dev/ysu_imu
/dev/ysu_lidar_front
/dev/ysu_lidar_back
For example:
SUBSYSTEM=="tty", ENV{ID_VENDOR_ID}=="0483", ENV{ID_MODEL_ID}=="5740", ENV{ID_SERIAL_SHORT}=="12345678", MODE:="0777", SYMLINK+="ysu_mcu"
SUBSYSTEM=="tty", ENV{ID_VENDOR_ID}=="10c4", ENV{ID_MODEL_ID}=="ea60", ENV{ID_SERIAL_SHORT}=="ABCDEF", MODE:="0777", SYMLINK+="ysu_imu"
SUBSYSTEM=="tty", ENV{ID_PATH}=="pci-0000:00:14.0-usb-0:3:1.0", MODE:="0777", SYMLINK+="ysu_lidar_front"
Then ROS 2 parameters write:
serial_port: /dev/ysu_mcu
imu_port: /dev/ysu_imu
lidar_port: /dev/ysu_lidar_front
This way, when the device node number is subsequently changed, ROS 2 the configuration file does not need to be modified at all.
5.10.ttyUSB difference between ttyACM and
Not all USB serial devices use:
/dev/ttyUSBn
Common types are as follows:
| Device Type | Kernel Name Example | Description |
|---|---|---|
| USB-to-Serial Chip | ttyUSB* |
CH340, CP210x, FTDI, etc. |
| USB CDC ACM | ttyACM* |
STM32 CDC, Arduino, etc. |
| Host Physical Serial Port | ttyS* |
PC onboard UART |
| USB Camera | video* |
V4L2 Camera |
| Disk | sd* |
USB hard drive, USB flash drive |
| Input Device | event* |
Keyboard, mouse, gamepad |
| Bluetooth Serial Port | rfcomm* |
Bluetooth RFCOMM |
So in the udev rule:
KERNEL=="ttyUSB*"
It is not a fixed notation.
If the STM32 CDC corresponds to:
/dev/ttyACM0
Then it should match:
KERNEL=="ttyACM*"
It can also be used uniformly:
SUBSYSTEM=="tty"
Then filter in combination with other attributes.
5.11.USB camera fixed device path
A USB camera typically corresponds to:
/dev/video0
/dev/video1
/dev/video2
...
Moreover, a single camera can sometimes generate multiple /dev/videoN nodes.
Therefore, it is not advisable to simply assume:
video0、video2、video4 一定是摄像头采集节点
This is because the device node numbering and interface order may change.
5.11.1.View the camera fixed path generated by the system
Execute:
ls -l /dev/v4l/by-id/
ls -l /dev/v4l/by-path/
For example:
/dev/v4l/by-id/usb-USB_Camera-video-index0
/dev/v4l/by-id/usb-USB_Camera-video-index1
If the camera has unique identity information, it is recommended to use:
/dev/v4l/by-id/
If differentiation is required based on a fixed USB interface:
/dev/v4l/by-path/
5.11.2.View camera node
Can install:
sudo apt install v4l-utils
Then:
v4l2-ctl --list-devices
For example:
USB Camera:
/dev/video0
/dev/video1
You can also further view the formats supported by a particular node:
v4l2-ctl -d /dev/video0 --all
5.12.Fixed path of the disk device
For USB hard drives, USB flash drives, SSDs, etc., it is not recommended to rely directly on:
/dev/sda
/dev/sdb
Linux also provides:
/dev/disk/by-id/
/dev/disk/by-path/
/dev/disk/by-uuid/
/dev/disk/by-label/
For example:
ls -l /dev/disk/by-id/
Therefore, different types of devices all follow similar principles:
动态设备节点
↓
系统生成固定路径
↓
必要时自己编写 udev rule
5.13.Activate udev rules
Modify:
/etc/udev/rules.d/*.rules
Afterward, both Ubuntu and Fedora can use:
sudo udevadm control --reload-rules
sudo udevadm trigger
Then reinsert the device.
For serial port devices, you can also:
sudo udevadm trigger --subsystem-match=tty
If the rule still does not take effect, you can directly restart the system.
5.14.Test fixed alias
View symbolic link:
ls -l /dev/ysu_mcu
View the final actual device:
readlink -f /dev/ysu_mcu
For example:
/dev/ttyACM1
Even if reinserting the device afterwards becomes:
/dev/ttyACM3
If the udev rule matches correctly:
/dev/ysu_mcu
it will still point to the correct device.
5.15.Troubleshoot udev rules
If the rule has not taken effect, you can check it by following the methods below.
5.15.1.Check rule syntax
sudo udevadm verify /etc/udev/rules.d/99-usb-serial.rules
If the current system version supports this command, the rule file can be checked directly.
5.15.2.View device properties
udevadm info --query=property --name=/dev/ttyUSB0
Or:
udevadm info --attribute-walk --name=/dev/ttyUSB0
Key checks:
idVendor
idProduct
serial
ID_SERIAL
ID_SERIAL_SHORT
ID_PATH
KERNELS
SUBSYSTEM
5.15.3.Monitoring device plug and unplug events
Execute:
udevadm monitor --environment --udev
Then, unplug and reinsert the USB device.
You can observe the udev attributes generated when the system recognizes the device.
5.15.4.View the device's actual permissions
ls -l /dev/ttyUSB0
For example:
crwxrwxrwx 1 root dialout ...
If used in rules:
MODE:="0777"
After the device is regenerated, permissions will be set according to the rules.
5.16.Recommended selection order
When fixing a USB device to a port, it is recommended to select in the following order.
USB设备
│
▼
是否已有系统固定路径?
/dev/serial/by-id
│
┌─────┴─────┐
│ │
有 无
│ │
▼ ▼
直接使用 是否存在唯一Serial?
│
┌─────┴─────┐
│ │
有 无
│ │
▼ ▼
按Serial绑定 是否固定USB接口?
│
┌─────┴─────┐
│ │
是 否
│ │
▼ ▼
by-path/ 尽量从设备固件
ID_PATH 层增加唯一Serial
In simple terms:
If the device itself can be identified, bind by the device itself; if the device itself cannot be identified, bind by the USB port to which the device is connected.
5.17.Final Recommended Solution
5.17.1.Case 1: A single device with a unique Serial
Preferred:
/dev/serial/by-id/
Or create your own:
/dev/ysu_mcu
5.17.2.Case 2: Multiple devices of different models
Can be used:
idVendor + idProduct
Create a custom udev rule.
5.17.3.Case 3: Multiple identical devices but with different serial numbers
Usage:
idVendor + idProduct + serial
This is a very stable solution.
5.17.4.Case 4: Multiple identical devices with no unique Serial
Usage:
/dev/serial/by-path/
Or:
KERNELS
ID_PATH
Distinguish based on the host's USB physical interface.
5.17.5.Case 5: STM32 Custom USB CDC
If the device firmware is under your own control, it is recommended to configure a unique Serial Number in the USB Descriptor.
This allows Linux to create a stable path based on the device's own identity, for example:
/dev/serial/by-id/usb-STMicroelectronics_STM32_Virtual_ComPort_xxxxx-if00
After that, no matter which USB port it is plugged into, the same control board can be recognized.
5.18.Summary
The persistent naming of Linux USB devices can essentially be divided into two categories:
根据设备是谁
↓
by-id
Serial Number
idVendor + idProduct + serial
根据设备插在哪里
↓
by-path
ID_PATH
KERNELS
Recommended priority in engineering:
/dev/serial/by-id/
↓
唯一 Serial Number
↓
/dev/serial/by-path/
↓
自定义 udev rules
In robotics projects, the following can ultimately be established in a unified manner:
/dev/ysu_mcu
/dev/ysu_gimbal
/dev/ysu_imu
/dev/ysu_lidar_front
/dev/ysu_lidar_back
Afterwards, ROS 2, C++ programs and startup files all use these fixed names and no longer rely on:
/dev/ttyUSB0
/dev/ttyUSB1
/dev/ttyACM0
/dev/ttyACM1
This way, even if the USB device is unplugged and reinserted, the boot order changes, or the system reallocates port numbers, the upper-layer program will not be affected.
6.Linux Partition GUI Tool
sudo apt install gparted
sudo dnf install gparted
7.DDNS
8.Mount intranet webpage
You can mount the local web page on the router side, or on other devices in the same intranet segment, and even mount it locally.
The following uses an Android device as an example. Since Android devices currently cannot directly open HTML, we can host the HTML on a local server and then view it through a browser.
Since the Android system is based on the Linux kernel, we can download an app called Termux to type some Linux commands:
https://github.com/termux/termux-app
First, after opening the app, update the software cache:
pkg update
Then switch the source
nano $PREFIX/etc/apt/sources.list
Replace the file content with the following:
deb https://mirrors.bfsu.edu.cn/termux/termux-packages-24 stable main
-
If you are using the
nanoeditor:-
Press
Ctrl+Oto save the file. -
Press
Enterto confirm the filename. -
Press
Ctrl+Xto exit the editor.
-
-
If you are using the
vimeditor:-
Press
Escto exit edit mode. -
Type
:wqto save and exit.
-
Next, update the software sources again:
pkg update && pkg upgrade
Install Python:
pkg install python3
Access device storage via Termux :
If the file is on an Android device, you can use Termux's file manager to access the device's storage:
termux-setup-storage
-
Navigate to the directory containing the HTML file :
- Use the
cdcommand to navigate to the directory where the HTML file is located:
- Use the
cd ~/your_html_folder
-
Start a Python HTTP server :
- Run the following command to start a simple HTTP server:
python3 -m http.server 8000- This will start a web server on port
8000.
- After starting the server, Termux will display log information, for example:
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
- This indicates that the server has started successfully.
Access HTML files in the browser
-
Access on the same device :
- Open a browser on the Android device (e.g., Chrome) and enter the following address:
http://localhost:8000- If the HTML file contains
index.htmlit will load automatically; otherwise, you need to manually click the file link.
9.RustDesk
9.1.RustDesk Unattended Remote Control
目前rustdesk还没办法进行无人值守在wayland下,所以我们需要把登陆密码,锁屏和休眠待机全部关掉.
9.1.1.Set up KDE6 automatic login
- You can first check your own SDDM type.
ls /usr/share/xsessions/
ls /usr/share/wayland-sessions/
See which one outputs content; the folder that outputs content is the sddm you have. For example, if xsessions outputs content, then it is the X11 sddm; if wayland-sessions outputs content, then you have the Wayland sddm.
- Edit the SDDM configuration:
sudo nano /etc/sddm.conf
在文件最上面有个[Autologin],在这个底下加入下面的内容:
[Autologin]
User=你的用户名
Session=plasma.desktop # 或 plasma.desktop(X11),方案一可用 Wayland
- After saving and exiting, restart SDDM:
sudo systemctl restart sddm
✅ Automatically enter the desktop after startup without entering a password
9.1.2.Disable the lock screen in KDE6 system settings:
Open System Settings → Screen Locking. Disable Automatic Locking. Disable Screen Off / Screen Saver Locking. This way, RustDesk can directly control the desktop after boot without being blocked by the lock screen.
9.1.3.Turn off hibernation System Settings → Power Management
Disable "Sleep" or "Automatic Suspend" Keep the computer powered on and online so RustDesk can provide remote control at any time If sleep is necessary, you can disable sleep in the BIOS settings to ensure it connects to the network upon startup
9.2.RustDesk self-hosted server
9.2.1.Install on the server side
9.2.1.1.Command-line mode
- Open the official website:https://rustdesk.com/docs/zh-cn/self-host/

- To access via SSH, you need to install RustDesk on the server.
ssh tungchiahui@10.0.0.4

- Use the command in Method 2

wget https://raw.githubusercontent.com/techahold/rustdeskinstall/master/install.sh
chmod +x install.sh
./install.sh
See the next section for the settings of ./install.sh
- Configure and View KEY
Here, if you want to directly use the public IP, select1)IP, and if you use DDNS or a domain name bound to an IP address, select2).

Select this2)No

This is the KEY. Copy it down, as it will be needed later during software configuration.

-
Configure the firewall
- If you are using a Debian-based system Install the firewall
sudo apt install ufwConfigure the firewall
sudo ufw allow 22 ufw allow 21114:21119/tcp ufw allow 21116/udp sudo ufw enable- If you are using a RHEL-based system Install the firewall
# 如果你是RHEL系 sudo dnf install firewalld sudo systemctl enable --now firewalldConfigure the firewall
sudo firewall-cmd --add-port=22/tcp --permanent sudo firewall-cmd --reload sudo firewall-cmd --add-port=21114-21119/tcp --permanent sudo firewall-cmd --reload sudo firewall-cmd --add-port=21116/udp --permanent sudo firewall-cmd --reload sudo systemctl enable --now firewalld
9.2.1.2.1Panel method
- Search for RustDesk in the panel and install it

- Configure the firewall

Add a few ports

- View KEY

Copy KEY

9.2.2.Configuring RustDesk software after self-hosting the server
- PC side


If "ready" appears, the configuration is successful 
- Mobile


9.2.2.1.Issues to Note
If it is an internal network server for the home, you also need to allow the corresponding port on the router.
Find the OpenWrt firewall settings, click Add 


Then you also need to allow IPv6. Debian generally leaves IPv6 unfiltered by default, but it will be blocked by the upstream OpenWrt, so you need to enable the corresponding rules in OpenWrt.
Go to|"防火墙 - 通信规则" and add the following two configurations.
Allow-RustDesk-IPv6-TCP
WAN → LAN
目标:你服务器的ipv6公网
TCP 21115-21119
动作:接受转发
Allow-RustDesk-IPv6-UDP
WAN → LAN
目标:你服务器的ipv6公网
UDP 21116
动作:接受转发


Only in this way can your server port truly be successfully allowed through.
10.WireGuard
10.1.Introduction
WireGuard is a tool used to access intranet devices outdoors through a VPN.
Here my tutorial will teach you how to access your home's intranet devices from outside.
10.2.My Environment
10.2.1.Intranet
Home LAN subnet:10.0.0.0/24

10.2.2.External device
If you are connecting to the office Wi-Fi in a place such as an office, then you need to know室外内网网段, if you are directly using mobile data, then you do not need to know anything.
Outdoor intranet subnet:192.168.31.0/24 Outdoor data traffic operator: China Unicom
10.3.Install
10.3.1.Server side - soft router side
Log in to OpenWrt via SSH, or use the LuCI interface:
opkg update
opkg install wireguard-tools luci-proto-wireguard kmod-wireguard qrencode
After installation, refresh the browser LuCI page.
10.3.2.Client - Mobile, Desktop
https://www.wireguard.com/install/
- Android
https://play.google.com/store/apps/details?id=com.wireguard.android&hl=zh&pli=1
- iOS
US region:https://apps.apple.com/us/app/wireguard/id1441195209 Japan region:https://apps.apple.com/jp/app/wireguard/id1441195209 Taiwan region:https://apps.apple.com/tw/app/wireguard/id1441195209
-
Linux
- Fedora
sudo dnf install wireguard-tools- Ubuntu/Debian
sudo apt install wireguard
10.4.Configuration
10.4.1.Server side - Initialization configuration
In the LuCI interface, click网络 → 接口 → 添加新接口
- For the protocol, select WireGuard VPN
- For the name, enter wg0
- Click Next to go to the details page

Configure in sequence according to the steps in the image above. Let me explain here. Listening port:51820(Customizable; just use an unused port. Remember this port. If you don't understand, just follow my settings.) IP address:10.10.10.1/24(VPN internal network segment; it must not conflict with your soft router's LAN segment. If you don't understand, just follow my settings.)
You must ensure that your家庭内网网段and your室外内网网段as well as the IP address just filled in, cannot belong to the same subnet.
For example, my家庭内网网段is10.0.0.0/24, while室外内网网段is192.168.31.0/24, and the VPN subnet10.10.10.0/24.
Then click firewall settings and selectWireGuard.

10.4.2.Server-side peer configuration
这里配置的就是你的手机/笔记本作为客户端连进来的信息:
这个界面很方便,LuCI可以直接帮你生成客户端的密钥对并直接导出配置文件/二维码,不需要你手动在手机上先生成公钥再倒腾过来,效率高很多。按下面顺序填:
- 描述 phone (或者你自己好记的名字,比如"iPhone17")
- 公钥 + 私钥 —— 直接点"生成新的密钥对" 点这个按钮,系统会自动帮你同时生成一对新的公钥+私钥,并自动填到"公钥"和"私钥"两个框里。 这个做法比你自己在手机App里生成再抄公钥过来省事得多,因为最后可以直接导出完整配置文件甚至二维码给手机扫码导入,私钥也是配置好的,不用手动输入。
- 预共享密钥(PSK) —— 建议点"生成预共享密钥" 这是可选的额外加密层,加上更安全(抗未来量子计算破解),点一下"生成预共享密钥"按钮自动填好即可,不需要手动操作。
- 允许的IP 点绿色+号,填: 10.10.10.2/32 这是分配给这台手机的隧道内网IP(如果以后要加第二台设备,比如笔记本,就用10.10.10.3/32,以此类推)。
- 为允许的IP创建路由 —— 勾选 这个决定了服务端要不要给这个IP自动建路由,勾上,否则服务端不知道怎么把去往10.10.10.2的包转发给这个peer。
- 对端地址 (Image 2) 这个字段填的是客户端的地址,但因为你的手机是移动设备、IP会变,服务端这边留空即可,不用填。(这个字段一般是给"两个固定IP的服务器互联"场景用的,你这种手机/笔记本客户端场景不需要)
- 对端端口 同理,留空或者保持默认51820占位符不用管,服务端这边这个字段对客户端场景没意义,跳过。
- 持续保持连接(Persistent Keepalive) 填: 25 因为手机大概率处在NAT环境下(无论是WiFi还是4G/5G),这个值能防止连接因为长时间无流量被NAT设备判定断开。
- 保存后 —— 点"生成配置..." 这一步是重点:全部填完先点右下角"保存",保存完之后再进来点 配置导出 那个"生成配置..."按钮,系统会:
Automatically generate a complete client configuration file (including all information such as the private key, server public key, Endpoint address, etc.) A QR code is usually also displayed.
The WireGuard app on your phone can scan this QR code to import the configuration in one step, without you having to manually enter any fields—it is the most hassle-free option.
-
填完这些保存之后,点"生成配置"

- 连接端点 —— 改成DDNS域名
没有ddns域名的请看ddns教程.
现在显示的是
112.233.39.5这个具体的公网IPv4,这是系统自动探测到的当前公网IP,但建议改成:ddns.xxxxxx.cn原因很简单:家庭宽带的公网IP大概率是动态的(如果你是中国移动,你完全不需要担心这件事情,你没有公网ipv4,你只有公网ipv6),过一阵子运营商重新分配IP后,这个写死的IP就失效了,配置文件也就废了。用DDNS域名的话,只要你路由器上的DDNS客户端正常更新,域名自动跟着IP变化解析,配置文件永久有效,不用来回改。 直接把这个下拉框里的值改成ddns.tungchiahui.cn即可,如果下拉框里没有这个选项,看能不能手动输入替换。 - 允许的IP —— 这个要看你的使用需求,建议改 现在是 0.0.0.0/0 + ::/0,意思是全局代理模式:连上VPN后,手机/电脑的所有上网流量(刷网页、看视频、聊天全部)都会先绕道回你家里,再从家里的网络出去上网。 这跟最初的需求("在外面访问家里NAS")不太一致,全局模式的影响:
✅ 优点:所有流量都通过加密隧道,公共WiFi环境下更安全 ❌ 缺点:手机所有网络流量的速度都取决于你家宽带的上传带宽,如果你家是常见的百兆宽带(上传可能才几十M甚至更低),刷视频、下载会明显变慢;而且家里NAT要承担所有流量的转发压力
如果你只是想访问家里内网的NAS/PVE/Debian,建议改成分离隧道模式,把这两行改成: 10.10.10.0/24 10.0.0.0/24 删掉 0.0.0.0/0 和 ::/0 这两行(点它们右边的红色×号),只保留上面这两个网段。这样只有"访问家里内网"这一类流量才走VPN隧道,其他正常上网流量不受影响,速度不受影响。 如果你确实希望VPN也当"全局代理"用(比如出门用境外的WiFi想用家里的网络环境访问某些内容),那就保留 0.0.0.0/0 不用改。
- DNS服务器:10.0.0.1 —— 这是你家庭内网的软路由的LAN地址,连VPN后用它解析域名没问题,能顺带解析你家内网可能配置的一些本地域名
- 地址:10.10.10.2/32 —— 这个就是你想给你的这个手机分配一个VPN网段
- 连接端点 —— 改成DDNS域名
没有ddns域名的请看ddns教程.
现在显示的是

Then take out the mobile client and import the configuration using the QR code.

10.4.3.Server - Firewall Settings
Rules to add Go to Network → Firewall → Traffic Rules, and click "Add":

Name: WireGuard (name it whatever you like) Protocol: UDP or TCP/UDP Source zone: wan Destination zone: Device (Input) — because WireGuard listens on a port on the soft router itself, rather than forwarding to other devices on the LAN Destination port: 51820 (the same as the "Listen Port" you entered for the wg0 interface) Action: Accept

Save and apply.
10.4.4.Client
Take iOS as an example.
Here I use mobile data for testing, using China Unicom 4G.
Just open the configuration you imported as you would use a normal VPN.

10.5.test
Then you can try to access your intranet devices, for example, my openwrt is 10.0.0.1, pve is 10.0.0.2, nas is 10.0.0.5, and all can be accessed normally.



10.6.Hand over WireGuard to Clash Meta for management (optional)
10.6.1.Put a pure WireGuard configuration into Clash Meta
If a client that supports the Mihomo / Clash Meta core has already been running on a phone or computer for a long time, starting a separate WireGuard client would be rather troublesome, and the same mobile device usually cannot enable two VPN tunnels at the same time.
Therefore, WireGuard nodes can be written directly into the Clash Meta configuration, letting Clash Meta uniformly handle:
- Direct connection for regular internet traffic;
- Home intranet traffic is accessed through WireGuard;
- Automatically determine which exit the traffic should take based on rules.
This section only describes pure WireGuard configurations that do not include airports or other proxy nodes.
After configuration is complete, you no longer need to open a separate WireGuard client. When using this configuration, you should turn off the tunnel in the WireGuard App and only open Clash Meta.
10.6.1.1.View WireGuard client parameters
First, open a WireGuard client configuration that is already working properly, and record the following information:
| Clash Meta field | Corresponding field in WireGuard client |
|---|---|
server |
Endpoint domain or public IP in Peer |
port |
Endpoint port in Peer |
ip |
Addresses in Interface, fill in only IPv4 address, do not write/32 |
private-key |
Private key in Interface |
public-key |
Public key in Peer, that is, the WireGuard server public key |
pre-shared-key |
Preshared key in Peer |
persistent-keepalive |
Persistent keepalive in Peer |
The most easily confused thing here is the two public keys:
- The Public key in the Interface is the current client's public key and cannot be filled into Clash Meta's
public-key; - The Public key in the Peer is the WireGuard server's public key and needs to be filled into Clash Meta's
public-key.
This single figure contains both the Interface and Peer parts, which is already sufficient to explain where each field should be obtained from; no additional screenshots are needed.
10.6.1.2.Create YAML configuration
Create a new file with the extension.yaml,for example:
home-wireguard.yaml
Write into the following template:
# 仅让家庭内网流量通过WireGuard
# 普通互联网流量保持直连
# 启用本配置时,不要同时开启独立的WireGuard客户端
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
ipv6: true
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
proxies:
- name: 家庭-WG
type: wireguard
# WireGuard客户端Peer中的Endpoint
server: ddns.example.com
port: 51820
# WireGuard客户端Interface中的Addresses
# 例如原配置为10.10.10.2/32,这里只填写10.10.10.2
ip: 10.10.10.2
# WireGuard客户端Interface中的Private key
private-key: "gBzeTbZH..."
# WireGuard客户端Peer中的Public key,即服务器公钥
# 不要填写Interface中的客户端公钥
public-key: "UUS0nrKE..."
# WireGuard客户端Peer中的Preshared key
pre-shared-key: "NGYvFsCle..."
allowed-ips:
- 0.0.0.0/0
udp: true
persistent-keepalive: 25
mtu: 1380
rules:
# 家庭局域网网段
- IP-CIDR,10.0.0.0/24,家庭-WG,no-resolve
# WireGuard隧道网段
- IP-CIDR,10.10.10.0/24,家庭-WG,no-resolve
# 其他网络流量保持直连
- MATCH,DIRECT
10.6.1.3.Modify the parameters in the template.
You need to modify the following content according to your own WireGuard configuration.
1. server
Will:
server: ddns.example.com
Change it to the domain name or public IP before the colon in the Endpoint of the WireGuard client Peer.
For example, the Endpoint is:
ddns.example.com:51820
Then fill in:
server: ddns.example.com
2. port
Fill in the port after the colon in the Endpoint, for example:
port: 51820
3. ip
Enter the Addresses in the WireGuard client Interface, but do not enter the CIDR suffix.
For example, the original configuration is:
10.10.10.2/32
Fill in Clash Meta:
ip: 10.10.10.2
4. private-key
Enter the Private key in the WireGuard client Interface:
private-key: "客户端私钥"
5. public-key
Fill in the Public key in the WireGuard client Peer, that is, the server public key:
public-key: "服务器公钥"
Do not mistakenly fill in the Public key in the Interface. The Public key in the Interface belongs to the current client, while the Public key in the Peer belongs to the server.
6. pre-shared-key
Enter the Preshared key in the WireGuard client Peer:
pre-shared-key: "预共享密钥"
A WireGuard key is a Base64 string; when copying it, do not miss the possible trailing=.
7. rules
Change the home LAN subnet and WireGuard tunnel subnet in the rules to your actual subnets.
For example:
rules:
- IP-CIDR,10.0.0.0/24,家庭-WG,no-resolve
- IP-CIDR,10.10.10.0/24,家庭-WG,no-resolve
- MATCH,DIRECT
Indicates:
- Access
10.0.0.0/24When accessing the home LAN, use WireGuard; - Access
10.10.10.0/24When accessing the WireGuard tunnel subnet, use WireGuard; - All other traffic is directly connected and does not go through the home broadband.
10.6.1.4.About allowed-ips
In the template:
allowed-ips:
- 0.0.0.0/0
It can remain unchanged.
它表示这个WireGuard代理节点能够承载全部IPv4流量,但实际哪些流量交给WireGuard,仍然由最下面的rules决定。
For example:
rules:
- IP-CIDR,10.0.0.0/24,家庭-WG,no-resolve
- IP-CIDR,10.10.10.0/24,家庭-WG,no-resolve
- MATCH,DIRECT
Under this set of rules, only the home intranet and the WireGuard tunnel subnet go through WireGuard, while other internet traffic continues to connect directly.
Note that the Allowed IPs in the WireGuard server-side Peer should still be the address assigned to that client, for example:
10.10.10.2/32
Do not change the Allowed IPs in the WireGuard server Peer to0.0.0.0/0.
10.6.1.5.Import and test
Import the YAML file into a client that supports the Mihomo / Clash Meta core, then:
- Disable the standalone WireGuard client tunnel;
- Select the configuration just imported in Clash Meta;
- Use "Rule" mode;
- Turn on the Clash Meta connection switch;
- Access home intranet devices for testing.
For example, accessing a soft router:
http://10.0.0.1
Or connect to a NAS in the iOS Files app:
smb://10.0.0.5
At the same time, you can access the WireGuard server to view the Latest Handshake of the corresponding peer.
If the handshake time refreshes after enabling Clash Meta and home intranet devices can be accessed, it means the configuration is successful.
10.6.1.6.FAQ
If YAML can start but fails to produce a WireGuard handshake, prioritize checking:
public-keyWhether it was mistakenly filled in as the client public key;private-keyWhether it is the current client private key;pre-shared-keyWhether it is complete, and whether the trailing=is omitted;ipWhether it is consistent with the address assigned to this peer by the server;- Whether the Endpoint domain name and port are correct;
- Whether the soft router firewall has already allowed the WireGuard port;
- Whether the standalone WireGuard client is still enabled.
If the error is similar to:
decode pre shared key: illegal base64 data
General descriptionpre-shared-keyThe copy is incomplete. A common cause is that the=at the end was omitted.
10.6.2.Add WireGuard to the YAML containing proxy nodes
11.Alist
11.1.Introduction
11.2.Install
11.3.WebUI
11.4.S3 protocol
11.4.1.Enable S3
First, enable the S3 protocol.

Go to/opt/1panel/apps/alist/alist/data/dataModify the settings in the directory as shown in the figure, changing fromfalsetotrue.
"s3": {
"enable": true,
"port": 5246,
"ssl": false
}

Finally, click restart.

11.4.2.Test S3 link
Type it on the deployed AList server itself
curl -i http://127.0.0.1:5246/
If it showsHTTP/1.1 200 OK then it proves it is OK.

Later, I also reverse-proxied it to a domain names3.tungchiahui.cn and after testing, there were no issues either:

11.4.3.Configure S3
In the AList management interface, find S3 in the settings, then click Add at the bottom to add which path as a bucket:
- Name is the name of the bucket
- Path is the path you want AList to use as the root directory of the bucket
- S3 access key id is the S3 authorization ID
- S3 secret access key is the S3 authorization key

11.4.4.Test S3
First, prepare your configuration.
Endpoint:
http://127.0.0.1:5246
或者
https://s3.tungchiahui.cn
Bucket:
ObjectStorage
Access Key:
AList 后台生成的 S3 Access Key ID
Secret Key:
AList 后台生成的 S3 Secret Access Key
Region:
us-east-1
Use software that can use S3, for example, I use the VScode plugin I made for testing.
The plugin link is as follows: https://marketplace.visualstudio.com/items?itemName=tungchiahui.md-image-uploader
I filled the configuration into VSCode'ssettings.jsonTested using my plugin:
{
"mdImageUploader.s3.accessKeyId": "2Vxxxxxxxxxxxxxxxxxxxxxx",
"mdImageUploader.s3.secretAccessKey": "FWx6xxxxxxxxxxxxxxxxxx",
"mdImageUploader.s3.endpoint": "https://s3.tungchiahui.cn",
"mdImageUploader.s3.region": "us-east-1",
"mdImageUploader.s3.bucket": "ObjectStorage",
"mdImageUploader.cdnUrl": "https://cdn.tungchiahui.cn",
"mdImageUploader.datedUploadPath": "/tungwebsite/assets/images",
"mdImageUploader.undatedUploadPath": "/tungwebsite/assets/images/undate"
}
After testing, the file has been successfully saved to the bucket.


11.4.5.Create file direct link
Go to AList backend
管理
→ 设置
→ 全局
→ 关闭Sign All
If Sign All is on, turn it off. Because as long as the global Sign All is on, individually storing signatures off below is useless. AList officially states that Sign All adds signatures to all file direct links.


Then find the storage location of the bucket where your AList is stored and edit it.

Close启用签名 / Enable signing.

Then save.
Then you can access the file through.
Advanced operations (optional):
Setcdn.tungchiahui.cnalso andalist.tungchiahui.cnsame-origin, then accelerate in Tencent Cloud EdgeOne, and add a new rule forcdn路径前缀增加in the rules engine.

- Host selection
cdn.tungchiahui.cn - Operation selection
回源URL重写 - Type selection
增加路径前缀 - Add path prefix selection
/d/AList文件的多余路径/
For example增加路径前缀what I filled in/d/NAS/ObjectStorage, Then I usehttps://cdn.tungchiahui.cn/tungwebsite/assets/images/2024/03/30/1787159371048-e2e3749f.webp will be equivalent tohttps://alist.tungchiahui.cn/d/NAS/ObjectStorage/tungwebsite/assets/images/2024/03/30/1787159371048-e2e3749f.webp, all will be back-to-origin to myhttps://服务器ip地址/d/NAS/ObjectStorage/tungwebsite/assets/images/2024/03/30/1787159371048-e2e3749f.webp.
Set another caching rule:

Cache rules can be understood as follows:
-
Node cache TTL: 30 days
EdgeOne will cache images on edge nodes for 30 days. Subsequent access will preferentially be returned from CDN nodes, which can significantly reduce the pressure on AList, the server, and server bandwidth. -
Force cache: Off
Keeping it off is safer. If the origin server explicitly requires that certain resources not be cached, EdgeOne will respect the origin server settings and avoid incorrectly caching special resources. -
Cache Key: Ignore all query strings
For example:xxx.webp xxx.webp?a=1 xxx.webp?a=2 xxx.webp?a=3will all be considered the same cached resource. This can prevent others from continuously modifying URL parameters to bypass the cache and repeatedly hitting your AList and server, and since my files are also stored on a NAS, it will further prevent them from repeatedly hitting my NAS.
-
Ignore case: Off
abc.webpandABC.webpwill be treated as two different files, avoiding different files being incorrectly merged into the same cache. -
PHP / JSP / ASP / ASPX: Do not cache
These usually belong to dynamic pages, and setting them separately as not cached can prevent dynamic content from being cached for a long time by the CDN. For a pure image CDN, this is basically a foolproof setting. -
Image browser cache TTL: 1 day
jpg,png,gif,bmp,svg,webpand other images will be cached in the user's browser for 1 day. When users visit repeatedly within a short period of time, the browser can directly read the local cache, and not even EdgeOne needs to be requested again.
The final cache chain is roughly as follows:
浏览器
↓ 本地缓存 1 天
EdgeOne
↓ 节点缓存 30 天
AList
↓
NAS
The vast majority of repeat visits will stop at the browser or EdgeOne, and will not actually go back to the home server and NAS.
12.Self-hosted MinIO object storage
12.1.Introduction
| 项目 | 腾讯 COS | 自建 MinIO |
|---|---|---|
| 对象存储 | ✅ | ✅ |
| S3 API | ✅ | ✅ |
| 图片/附件 | ✅ | ✅ |
| Bucket | ✅ | ✅ |
| SDK 上传 | ✅ | ✅ |
| 私有对象/签名 URL | ✅ | ✅ |
| Versioning | ✅ | ✅ |
| 存储空间 | 腾讯提供 | 吃你服务器硬盘 |
| 带宽 | 腾讯提供 | 吃学校服务器出口带宽 |
| 高可用 | 腾讯负责 | 你负责 |
| 数据冗余 | 腾讯负责 | 你负责 |
| 硬盘损坏 | 云厂商处理 | 可能直接丢数据 |
| 运维 | 几乎没有 | Docker、磁盘、备份、升级、安全都自己搞 |
| 费用 | 存储+流量 | 软件可以自建,但硬盘/服务器/带宽自己承担 |
| CDN | 很容易接腾讯 CDN/EO | MinIO 本身不是 CDN |
| 可控性 | 一般 | 非常高 |
12.2.Install
First, you need to install on the server a1panel.
Enter the store and search for MinIO.

Click to install.
Most settings can be left at their defaults, but you need to fill in the account and password yourself. As for this external access port here, if your server is on an internal network, you can choose to enable it; if your server's IP is a public IP, then it is not recommended that you enable it.

| Configuration Item | Recommendation |
|---|---|
| Name | minio |
| Version | Choose a stable version currently provided by 1Panel |
| User | Set one yourself, do not use one that is too simple |
| Password | Set a more complex password yourself |
| WebUI Port | 9001 |
| S3 API Port | 9000 |
| Session Duration | Default 12h is fine |
| Enable WebUI | On |
| WebUI Animation | As you like |
| External Port Access | It is recommended not to expose it to the public network, but if you are testing, enabling public network exposure first is also fine. |
Finally, click Install.

12.3.Configure MinIO
12.3.1.Log in to MinIO
Enter in the browser服务器ip:9001:
For example, this intranet of mine10.0.0.4:9001

Then log in with the account and password.
12.3.2.Test bucket
Create a bucket, for example, here I call ittest

Let's just upload a random image and try again.



12.3.3.Test S3 protocol
The URL of the S3 protocol should be服务器ip:9000:
For example, this intranet of mine10.0.0.4:9000
Test S3 API health status on your computer:
curl -i http://10.0.0.4:9000/minio/health/live
If it showsHTTP/1.1 200 OK then it proves it is OK.

同样,测试下面这个是否S3就绪:
curl -i http://10.0.0.4:9000/minio/health/ready
If it showsHTTP/1.1 200 OK then it proves it is OK.

12.3.4.Connect to AList test


This must be kept on.

After configuration, you can return to the file list and find that the file just now can be viewed normally.
