Recently I noticed I would occasionally get the dreaded question-mark network icon: “?” I did some digging around and it was related to Ubuntu’s Network Connectivity check. Several posts out there simply say to disable the check by going to Settings -> Privacy and turning Connectivity Checking to “Off.”
But by disabling connectivity checking, I don’t get the automatic prompt to connect through a captive portal (like at my local library). I wanted to actually fix the problem, so I needed to understand what the problem was.
Ubuntu uses the URL http://connectivity-check.ubuntu.com/ by default for connectivity checking. I went to the command line to see if there were any problems using curl while on my wired network:
$ curl -v http://connectivity-check.ubuntu.com/
* Trying 220.127.116.11...
* TCP_NODELAY set
* connect to 18.104.22.168 port 80 failed: Connection timed out
* Trying 22.214.171.124...
* TCP_NODELAY set
* Connected to connectivity-check.ubuntu.com (126.96.36.199) port 80 (#0)
> GET / HTTP/1.1
> Host: connectivity-check.ubuntu.com
> User-Agent: curl/7.58.0
> Accept: */*
< HTTP/1.1 204 No Content
< Date: Wed, 09 Dec 2020 16:02:34 GMT
< Server: Apache/2.4.18 (Ubuntu)
< X-NetworkManager-Status: online
* Connection #0 to host connectivity-check.ubuntu.com left intact
Everything seemed to work out in the end, but you can see that the first request failed so it had to fall back to the secondary address. This whole request took 122 seconds.
The problem is, the default connectivity check interval is 120 seconds. So after the first one times out Network Manager flags the computer as offline. Apps like Spotify recognize the offline network status and stop working – despite being actually connected to the internet.
I gave it a little longer interval – 5 minutes instead of 2. It’s probably not necessary as their service responds much faster, but I want to avoid the question-mark-of-no-connectivity as much as possible but still retain features like captive portal detection.
Restart after you’ve saved that file and you should be good to go!
Most of the configuration follows this Nerdvittles Skyetel post, but I include some specifics and screenshots for my configuration using OpenWrt, IncrediblePBX on Raspberry Pi, and a Linksys RTP-300 analog telephone adapter.
On my OpenWrt router that acts as a gateway, I added a firewall port forward for UDP Port 5060 to my Asterisk server (Raspberry Pi).
I didn’t need to run any of the Skyetel add-ip customizations from the original article. On my Raspberry Pi those settings were already there. You can check to see if the firewall settings for the Skyetel IPs are already present by running:
If you see the ACCEPT all row, then you’re good to go. If you don’t get any output, you’ll need to run the commands from the Nerdvittles Skyetel post.
I also didn’t need to run any of the Skytel Trunk Setup scripts, as I already had the six Skyetel trunks configured and enabled.
I also didn’t need to change the context configuration from from-trunk to from-pstn-e164-us (for a normal 10-digit US phone setup). It was already there 💪 Also, nat=yes was already set, so no need to add that either.
For the DID and Description I added my full 11-digit number: 1 and the other 10-digits. I also set the destination to the “777 All-Five” ring group. It’s a default ring group setup to ring all extensions (701 to 705) all at once.
Once you click Submit there will be an “Apply Config” notification.
Click it to apply your new route and reload the dial plan.
The default Incredible PBX config already had default route. Click edit to view it:
As you can see it already has some Skyetel trunks pre-configured. Go ahead and click Duplicate to make a copy of this route we can change.
This will create a copy that we’ll edit.
Rename the route, add your 11-digit phone number, and add the additional Skyetel trunks, removing any extras.
After submitting the new route, use the crosshair icon to move the Skyetel route to the top, then click Apply Config.
I didn’t need to do any configuration of SIP Settings in Asterisk, my defaults all looked good.
Skyetel configuration is normally pretty simple, but for my configuration I want to combine my Dynamic DNS setup with the inbound SIP IP. But it turns out that Skyetel doesn’t work that way. Instead they support a script that will periodically call out from your asterisk server and update the endpoint IP at Skyetel if it’s changed https://bitbucket.org/skyetel/ip-endpoint-group-update/
In order to use the script, you must first create a set of API keys on the Skyetel dashboard by clicking the gear icon by your login name.
Go to the API keys tab and click Create. Save the keys somewhere safe, they won’t be displayed a second time.
Then head back to your Raspberry Pi to install the script. You’ll need git to install the script. Additionally, I also needed jq on my Raspberry Pi:
cd into the ip-endpoint-group-update directory, and then run the script. I used the defaults for port and transport by simply pressing <Enter>. Enter your API keys that you created on the Skyetel dashboard. I hadn’t yet set up an Endpoint Group in my Skyetel dash, so I entered “x” to do it from the script.
The script automatically installs itself into /usr/local/bin/ip-update-endpointgroup.sh and creates a cron to run it every twenty minutes at /etc/cron.d/ip-update-endpointgroup.cron
In the Skyetel dash I see there’s an endpoint group that was automatically created:
Before I began, I thought I should see if there’s a newer OpenWrt version my router can run. I always start on the Supported Devices page of the wiki, but on this visit I was treated to a warning:
If you read the 4/32 warning, the crux of the matter is that there may not be enough RAM to run OpenWrt without crashing. And the small flash area means possibly not having enough room to install LuCI, the web interface, and the packages to access LuCI via HTTPS. Also, there’s this:
Previous versions of OpenWrt (such as earlier versions of 17.01.x, 15.05.x “Chaos Calmer” and prior) contain now-known security vulnerabilities in the kernel, wireless implementation, and/or application code. […] In many cases, these known vulnerabilities are being actively targeted, potentially including by advanced, likely state-sponsored or state-affiliated actor or actors.
Ugh, I was using one of those older versions, and now I’m paranoid (as I should be) that my router could be used as a tool by nation-states to do their bidding. Nicely, there’s a link on the supported devices page titled “I want to buy a router which is supported by OpenWrt.” It links to their supported hardware table, pre-filtered by units that can run the latest stable version of OpenWrt – 19.07.4 at time of writing.
I spent some time browsing this list compared to what was available at my local Micro Center. I tried to find one that had the best OpenWrt support with the fewest known issues, and landed on the TP-Link C7 AC1750 for $70. If I like this one after a month or so, I’m going to buy another for better coverage.
OpenWrt ddns-scripts install
With the hardware choice out of the way, I installed OpenWrt 19.07.4. Then I needed to add support for Dynamic DNS. Go to System -> Software in the Web UI (LuCI). Click Update lists…, then type ddns in the filter input and press <Enter> to filter the list. The packages to install to use nsupdate.info are ddns-scripts_nsupdate and luci-i18n-ddns-en (or whatever language package you need):
Installing those will also install their dependencies, such as the base ddns-scripts and luci-app-ddns. Once they’re installed, reboot your router and you’ll have a Services -> Dynamic DNS menu.
You might see the menu before rebooting, but you’ll likely get this error if you try to visit it:
/usr/lib/lua/luci/controller/ddns.lua:116: attempt to index field '?' (a nil value)
Following it will lead you to a hints page and let you know you need to install a couple more packages: curl and bind-host. Follow the same installation process as above. After they’re installed, the Hints section will go away.
The only configuration you have to do at your DNS provider is add a CNAME record for the domain you want to use:
your.domain.com CNAME yourdomain.nsupdate.info
Then when you go to nsupdate.info, on the Overview page click Add Host and put in the subdomain (example: yourdomain from above) in the Name field, then select nsupdate.info under Domain:
Conveniently, after creating your new host entry, nsupdate.info will print your update secret and include specific configuration parameters for OpenWrt:
You can use the configuration info from nsupdate.info, but it’s just as easy to paste the info into the LuCI panel. It’s worth noting that you only need to generate one host and host secret at nsupdate.info, but you’ll have two separate configurations in OpenWrt for IPv4 and IPv6.
In OpenWrt’s Dynamic DNS page, click Edit on the myddns_ipv4 row. The first thing you’ll want to do is update the DDNS Service provider to nsupdate.info and click Change provider:
Only then can you enter all of the information from nsupdate.info:
Enter your nsupdate.info FQDN in all of these fields:
Then put your secret in the Password field. Check both Enabled and Use HTTP Secure, then add /etc/ssl/certs to Path to CA-Certificate. Click Save & Apply, then repeat the same process with the same info for the other myddns_ipv6 entry.
From the Dynamic DNS overview page in OpenWrt, click the Start buttons for each row under Process ID Start / Stop. This only needs to be done once when you’re done configuring Dynamic DNS.
Starting the Dynamic DNS process in OpenWrt should trigger your first update at nsupdate.info. You can see it easily on the Overview page:
If it all worked, your IPv4 and IPv6 address should be updated, hopefully with a green TLS indicator noting that it was done securely. If there are any problems, the numbers under Faults will increase – C for Client, S for Server.
If there are problems, you can see API messages on nsupdate.info by clicking on your hostname to get further details. You can also view detailed logs in OpenWrt by clicking Edit on the myddns_ipv4 or myddns_ipv6 rows. Then click the Log File Viewer tab and click the Read / Reread Log File button.
I was able to configure this in under an hour, hopefully you find it useful. Let me know if you have any troubles getting things to work.
Once upon a time you could hook your Asterisk-based PBX to your Google Voice account to make and receive calls. How you hooked it up over the years changed (annoyingly). And at the end of 2018, support for accessing Google Voice via XMPP was dropped. Remember when we trusted Google to be the “for the better good” company? Oh, how times have changed.
I did it with the help of Nerdvittles and included several screenshots here for easy reference. I also used his advice when it came to picking a new VOIP provider. After looking at a few options, I’m going with Skyetel. Not because it’s the cheapest (it’s not), but because it has an important feature for our home phone: E911.
Pro-tip: don’t port your number over to Skyetel until you’ve made your first deposit into you Skyetel account. Once you make your first actual payment, they offer a 60-day free port-in service (normally $10).
Back when I had a land line from the local telephone company, it would cost at least $20/month. I expect the Skyetel monthly charges for a local number ($1) and E911 service ($1.50), plus call time, to be less than $5/mo. It’s worth it to me if I can reliably call the house and anyone can dial 911 in an emergency.
My initial deposit of $50, doubled to $100 should last me over 2 years.
It will cost $3 to unlock – worth it to me because it’s a cool number.
Once your purchase has been confirmed you’ll be emailed a receipt.
And now your number is unlocked!
Porting your number into Skyetel
From your Skyetel dash, go to Port Orders and click Submit New Order.
The process is fairly simple, but here are some key settings:
Port Type: Local
Assign to Endpoint Group: Out of Service Message – This is so we don’t need to do any SIP configuration up-front. I’m going to cover Skyetel setup in IncrediblePBX in a future post.
Current Provider: Google Voice
Account number with the losing provider: Your 10-digit Google Voice Number.
Port Out Pin: The PIN you use to access your Google Voice voicemail.
Phone Bill: I provided a screenshot of my Google Voice settings page.
Select the first available date for porting to happen, then submit. A support ticket will be automatically generated from your port-in request and you’ll get email updates during the process until it’s complete.
Stay tuned and we’ll go over tying all of the services and equipment together for a reliable VOIP-based home phone:
WordCamp US 2020 was canceled, citing online event fatigue. But the organizers of WordCamp Minneapolis / St. Paul did not. Would we just be another notch in the bedpost of 2020 online event fatigue?
To be honest, the organizing team did contemplate canceling WordCamp Minneapolis / St. Paul as the Coronavirus pandemic continued to linger. But everyone agreed that pivoting to a single-day virtual event was a better idea – and we stayed the course.
When we had a real-life venue selected, there was an excellent computer lab available with over twenty computers. Going virtual meant re-thinking the game-plan. With WordCamp US canceled, it looks like WordCamp MSP’s KidsCamp might wind up being the only virtual KidsCamp of 2020.
Since it was uncharted territory, we cut the attendance in half, to 10 available spots. We reserved them for locals only, as our regular in-person conference is truly supposed to highlight pillars of our local community. With 80% local speakers at the conference, I think our organizers nailed it.
Check out the inside pages – including the first page which has a place to write down all of your new hosting and WordPress site details.
To make sure things would run smoothly, I went through the entire curriculum with my 11 year old son. We did it the same day the rest of the team was doing their streaming dry-run, two days before the live event. I even had my son go to his grandma’s and log in there via Zoom so we could simulate teaching remotely.
What did I learn from that experience? While I can power through a 3-hour zoom call with no issues, kids need to take a break. When my son asked to take a break I realized that I also was hungry, thirsty, or needed to use the restroom. So I added TAKE A BREAK in all-caps to my schedule notes in various places.
The Live Event
The day of the event went off without a hitch. We had 8 registrants and only 6 showed up. A 25% no-show rate is typical for WordCamp, so I didn’t sweat it.
We did some self-reflection and brainstorming. We talked about people we follow on YouTube and social media and what we like about them. My son cited DanTDM who plays a variety of games, not just Minecraft. When it came to self-reflection, I was pleasantly surprised that my son listed gaming as one of his interests, not just Fortnite. He wound up setting up a site with the central ideal of helping people with their gaming strategies. I likened it to Chris Lema’s mantra of Be Helpful – it warmed my heart 😍
Other kids chose different central ideas based on their interests: Animals, Music, Gaming – it was good to see a variety from the group.
We went with GoDaddy as our KidsCamp hosting sponsor, and they provided slick managed WordPress sites that didn’t require us to FTP any zip files to get started. This was one of the most important pieces of doing the camp virtually. We literally had zero technical issues to troubleshoot. 💪
Then we were off, publishing an about page and our first post. Then customizing our themes to reflect our tastes.
Besides taking breaks, doing the event virtually was challenging because I wanted all of the kids to stay in sync. When you’re in a lab, it’s easy to see what screen someone is on and help them move forward.
My approach to doing it virtually was to share my screen and have everyone let me know when they’re on the same screen so we can all move forward together. It was challenging at times because some kids would give a thumbs-up on their camera, some would type “done” in chat, some would confirm aloud, and others wouldn’t respond. I left plenty of breathing room and we managed to stay together.
I’m glad we were able to put this event on, and I’m hoping dearly that we can do KidsCamp again in person at Metro State in 2021 🤞