Recently, I found that the DDNS service provided by Asus is not working properly. When My public IP has changed, the DNS is not updated in time. It caused my VPN clients to disconnect from the server. Therefore, I wrote a DDNS service based on Spring Boot for my personal use. It works fine when run by jar file or docker. In my scenario, there is a Truenas Scale server locally. So, I just put a docker on it. It has been working fine for about several weeks.
For the users who may encounter the same issue with the built-in DDNS server, you can just try my open-source DDNS service. There is the GitHub link https://github.com/caltong/ddns. Please refer to the readme file. You are welcome to report issues or bugs. BTW, for now, it only supports Cloudflare DNS, because I’m using Cloudflare only right now. Please let me know if you want to use another DNS provider. It will be better if you provide me test account for my development.
This guide is to discuss how to connect multiple Asus routers via OpenVPN. In general, other brand routers should also work fine with OpenVPN if they support it in their official firmware. If not, it should be a little difficult to install third-party firmware like OpenWrt or Padavan for someone not familiar with them. After all, I’ll use Asus’s official firmware in this guide. Please let me know if you need other firmware guides.
First, let’s say we have 3 routers named router0, router1 and router2. And each of them has a different ISP connected. Networking settings show in the image below. Remember those network settings are made up for convenience. Put your setting into the router’s dashboard.
Router0’s public IP is 1.0.0.0, the gateway is 192.168.0.1 and the subnet is 192.168.0.1/24.
Router1’s public IP is 1.0.0.1, the gateway is 192.168.1.1 and the subnet is 192.168.1.1/24.
Router2’s public IP is 1.0.0.2, the gateway is 192.168.2.1 and the subnet is 192.168.2.1/24.
In this guide, not all routers need to have public IPs. But do need one for the server. For example, if router0 has a public IP, and others don’t. Then, router0 will be set as an OpenVPN server, others are OpenVPN clients.
DDNS(optional)
Unfortunately, some ISP don’t provide static public IP freely or even don’t provide dynamic public IP. There are 3 cases.
If you have a static public IP, you don’t need this part.
If you have a dynamic public IP, you need to keep reading this part.
If you have no public IP, please talk to your ISP or use frp/ngrok to get your service exposed to the public. And this guide may not fit your situation.
DDNS is Dynamic DNS, which can dynamically update DNS records without the need for human interaction. If your public IP changes, the DNS of your domain keeps updating automatically.
As I said before, we’re using Asus’s official firmware. We’re going to use DDNS provided by Asus which is free.
Find WAN under advanced settings, and choose DDNS tab. By default, the Server choice is WWW.ASUS.COM. If not, select it. Enter the domain you want into the Host Name box then click Register. In this screenshot, I have registered, so it shows Deregister button. If the domain name you want is already registered, then it will indicate a failure. You can only choose an alternative domain name that is not registered. http://iplookup.asus.com/nslookup.php is a quick way to test if your domain is taken.
If everything goes well, a domain has been created and pointed to your router’s public IP. Let’s say the domain is example.asuscomm.com.
Config on server
Find VPN under advanced settings. And choose VPN Server and OpenVPN.
The only thing that needs to do here is to set the server port to whatever you like. Let’s say set 10000 as the server port for example.
Then scroll down and add the client’s username and password. In this guide, we have other 2 routers as clients. So add 2 accounts here.
username: router1, password: router1password
username: router2, password: router2password
Don’t forget to click the Apply button, if not the config won’t be activated.
Then go do VPN Details and change General to Advanced Setings, you will find more settings.
There are 4 things to do:
Check if the Server Port is the one you set before.
Change Username / Password Auth. Only from No to Yes
Change the **VPN Subnet / Netmask, keeping the default is acceptable.
Then you need to export client’s config. Change VPN Details from Advanced Settings to General. And click export of Export OpenVPN configuration file. You will get a config file named client.ovpn by default. Then open this file and look at the first line. By default it will look like this:
remote 1.1.1.1(you public ip)
Change 1.1.1.1 to your DDNS domain/url like example.asuscomm.com.
Config on client
It’s easy on client’s side. Just go to VPN page choose VPN Client -> Add profile -> Input Username, Password and upload your modified client.ovpn. Click OK and if this file is not activated click Activate
In the end
Everything is done, enjoy your custom sd-wan.
If you encounter any problems following this tutorial, feel free to leave a comment.
Found this exception when using Redisson to implement the distributed lock:
java.lang.IllegalMonitorStateException: attempt to unlock lock, not locked by current thread by node id: d8fa7ae5-3152-468a-8793-6102b512df68 thread-id: 1
It happens when trying to unlock a lock that is already unlocked. It can be reproduced by the codes below.
The code above shows us the problem when setting a lock with a specific timeout value. But if we don’t set a timeout value, then this lock won’t be released by default from redisson. The Redis locks with no expiration time may cause deadlock issues when the thread has some exceptions. Redisson provides us with a watchdog to avoid the deadlock issue. It makes codes a lot more simple for us. No need to worry about the deadlock issue. The code below shows us the source code of the mechanism of the watchdog.
@Test
public void watchDog() throws InterruptedException {
RLock lock = redissonClient.getLock("watchDog");
lock.lock();
for (int i = 0; i < 30; i++) {
Thread.sleep(1000);
System.out.println(lock.remainTimeToLive());
}
}
We can see that although the code does not explicitly specify the lock expiration time, Redisson sets it to 30 seconds by default, and then every 10 seconds, the lock expiration time will be renewed for 10 seconds, that is, as long as the lock-holding thread does not release the lock voluntarily or an exception occurs, then the lock will not be released. This is guaranteed by Redisson’s watchdog mechanism.
We can get this code from Redisson config file:
/**
* This parameter is only used if lock has been acquired without leaseTimeout parameter definition.
* Lock expires after <code>lockWatchdogTimeout</code> if watchdog
* didn't extend it to next <code>lockWatchdogTimeout</code> time interval.
* <p>
* This prevents against infinity locked locks due to Redisson client crush or
* any other reason when lock can't be released in proper way.
* <p>
* Default is 30000 milliseconds
*
* @param lockWatchdogTimeout timeout in milliseconds
* @return config
*/
public Config setLockWatchdogTimeout(long lockWatchdogTimeout) {
this.lockWatchdogTimeout = lockWatchdogTimeout;
return this;
}
As you can see, the watchdog mechanism only intervenes when leaseTimeout is not set, as we can see from the source code below:
private void renewExpiration() {
ExpirationEntry ee = EXPIRATION_RENEWAL_MAP.get(getEntryName());
if (ee == null) {
return;
}
Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
ExpirationEntry ent = EXPIRATION_RENEWAL_MAP.get(getEntryName());
if (ent == null) {
return;
}
Long threadId = ent.getFirstThreadId();
if (threadId == null) {
return;
}
RFuture<Boolean> future = renewExpirationAsync(threadId);
future.whenComplete((res, e) -> {
if (e != null) {
log.error("Can't update lock " + getRawName() + " expiration", e);
EXPIRATION_RENEWAL_MAP.remove(getEntryName());
return;
}
if (res) {
// reschedule itself
renewExpiration();
} else {
cancelExpirationRenewal(null);
}
});
}
}, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);
ee.setTimeout(task);
}
By default, the lock will be renewed after internalLockLeaseTime / 3, TimeUnit.MILLISECONDS, which is 30/3 seconds after the default setting.
In order to compare the difference between HDD and SSD, the HDD and SSD are tested separately, and the machine is an ESXi virtual machine with the same configuration:
--Testing the unordered uuid vi pgbench_uuid_v4.sql insert into test_uuid_v4 (id) values (replace(uuid_generate_v4()::text,'-','')); --Testing ordered uuid vi pgbench_time_nextval.sql insert into test_time_nextval (id) values (replace(uuid_time_nextval()::text,'-','')); --Test sequence vi pgbench_seq_bigint.sql insert into test_seq_bigint (id) values (nextval('test_seq'::regclass));