ns-gce is dead! Long live ns-ovh-sg!

I'm worried the traffic to my GCP server will cost me a hundred dollars
in bandwidth fees. It has a volume similar to my late AWS server which,
in its last month, racked up ~$130 in bandwidth fees!

I'm also trying to balance the servers more geographically: instead of
having two servers in the US and none in Asia, I'll have one server in
the US and one in Asia (Singapore).

The OVH server in Asia is expensive — $60/month instead of $20/month for
the OVH server in Warsaw. Also there's a monthly bandwidth cap in
Singapore in addition to the 300 Mbps cap.

I went with a dedicated server, similar to the one in Warsaw, but I took
the opportunity to upgrade it (same price):

- ns-ovh:    KS-4: Intel Xeon-E3 1230 v6
- ns-ovh-sg: KS-5: Intel Xeon-E3 1270 v6

I'm hoping that by adding this server to Singapore, the traffic to the
ns-ovh, the Warsaw server, will lessen, and I won't get thos "Anti-DDoS
protection enabled for IP address 51.75.53.19" emails every few days.

Current Queries per second:

- 4,087 ns-gce
- 1,131 ns-hetzner
- 7,183 ns-ovh
This commit is contained in:
Brian Cunnie
2025-04-27 06:04:39 -07:00
parent 6d03384268
commit 50e6d71ee4
10 changed files with 52 additions and 46 deletions

View File

@@ -26,7 +26,7 @@ LABEL org.opencontainers.image.authors="Brian Cunnie <brian.cunnie@gmail.com>"
RUN dnf install -y bind-utils
ARG TARGETARCH # amd64, arm64 (so I can run on AWS graviton2)
RUN curl -f -L https://github.com/cunnie/sslip.io/releases/download/3.2.6/sslip.io-dns-server-linux-$TARGETARCH \
RUN curl -f -L https://github.com/cunnie/sslip.io/releases/download/3.2.7/sslip.io-dns-server-linux-$TARGETARCH \
-o /usr/sbin/sslip.io-dns-server; \
chmod 755 /usr/sbin/sslip.io-dns-server

View File

@@ -121,8 +121,8 @@ as ARM64 (AWS Graviton, Apple M1/M2).
privileged ports (<1024) ("`listen udp :53: bind: permission denied`"). For
example, to run the server on port 9553: `go run main.go -port 9553`. To query,
`dig @localhost 127.0.0.1.sslip.io -p 9553`
- `-nameservers` overrides the default NS records
`ns-gce.sslip.io`, `ns-hetzner.sslip.io`, and `ns-ovh.sslip.io`; flag, e.g. `go run main.go
- `-nameservers` overrides the default NS records `ns-hetzner.sslip.io`,
`ns-ovh.sslip.io`, and `ns-ovh-sg.sslip.io`; flag, e.g. `go run main.go
-nameservers ns1.example.com,ns2.example.com`). If you're running your own
nameservers, you probably want to set this. Don't forget to set address records
for the new name servers with the `-addresses` flag (see below). Exception:

View File

@@ -4,7 +4,7 @@
#
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
cd $DIR/..
ldflags="-X xip/xip.VersionSemantic=3.2.6 \
ldflags="-X xip/xip.VersionSemantic=3.2.7 \
-X xip/xip.VersionDate=$(date +%Y/%m/%d-%H:%M:%S%z) \
-X xip/xip.VersionGitHash=$(git rev-parse --short HEAD)"
export GOOS GOARCH

View File

@@ -4,8 +4,8 @@ These instructions are meant primarily for me when deploying a new release;
they might not make sense unless you're on my workstation.
```bash
export OLD_VERSION=3.2.5
export VERSION=3.2.6
export OLD_VERSION=3.2.6
export VERSION=3.2.7
cd ~/workspace/sslip.io
git pull -r --autostash
# update the version number for the TXT record for version.status.sslip.io
@@ -14,8 +14,7 @@ sed -i '' "s/$OLD_VERSION/$VERSION/g" \
spec/check-dns_spec.rb
# update the download instructions on the website
sed -i '' "s~/$OLD_VERSION/~/$VERSION/~g" \
k8s/document_root_sslip.io/index.html \
k8s/Dockerfile-sslip.io-dns-server
Docker/sslip.io-dns-server/Dockerfile
```
Optional: Update the version for the ns-gce, ns-hetzner, and ns-ovh install scripts
@@ -23,7 +22,7 @@ Optional: Update the version for the ns-gce, ns-hetzner, and ns-ovh install scri
```bash
pushd ~/bin
sed -i '' "s~/$OLD_VERSION/~/$VERSION/~g" \
~/bin/install_ns-{gce,hetzner,ovh}.sh
~/bin/install_ns-{gce,hetzner,ovh}.sh ~/bin/install_common.sh
git add -p
git ci -m"Update sslip.io DNS server $OLD_VERSION$VERSION"
git push
@@ -42,13 +41,13 @@ Test from another window:
```bash
export DNS_SERVER_IP=127.0.0.1
export VERSION=3.2.6
export VERSION=3.2.7
# quick sanity test
dig +short 127.0.0.1.example.com @$DNS_SERVER_IP
echo 127.0.0.1
# NS ordering might be rotated
dig +short ns example.com @$DNS_SERVER_IP
printf "ns-gce.sslip.io.\nns-hetzner.sslip.io.\nns-ovh.sslip.io.\n"
printf "ns-hetzner.sslip.io.\nns-ovh.sslip.io.\nns-ovh-sg.sslip.io.\n"
dig +short mx example.com @$DNS_SERVER_IP
echo "0 example.com."
dig +short mx sslip.io @$DNS_SERVER_IP
@@ -88,6 +87,7 @@ git push --tags
scp bin/sslip.io-dns-server-linux-amd64 ns-gce:
scp bin/sslip.io-dns-server-linux-amd64 ns-hetzner:
scp bin/sslip.io-dns-server-linux-amd64 ns-ovh:
scp bin/sslip.io-dns-server-linux-amd64 ns-ovh-sg:
ssh ns-gce sudo install sslip.io-dns-server-linux-amd64 /usr/bin/sslip.io-dns-server
ssh ns-gce sudo shutdown -r now
# check version number:
@@ -100,6 +100,10 @@ ssh ns-ovh sudo install sslip.io-dns-server-linux-amd64 /usr/bin/sslip.io-dns-se
ssh ns-ovh sudo shutdown -r now
# check version number:
sleep 10; while ! dig txt @ns-ovh.sslip.io version.status.sslip.io +short; do sleep 5; done
ssh ns-ovh-sg sudo install sslip.io-dns-server-linux-amd64 /usr/bin/sslip.io-dns-server
ssh ns-ovh-sg sudo shutdown -r now
# check version number:
sleep 10; while ! dig txt @ns-ovh-sg.sslip.io version.status.sslip.io +short; do sleep 5; done
```
- Browse to <https://github.com/cunnie/sslip.io/releases/new> to draft a new release
@@ -114,7 +118,7 @@ Update the webservers with the HTML with new versions:
```bash
ssh nono.io curl -L -o /www/sslip.io/document_root/index.html https://raw.githubusercontent.com/cunnie/sslip.io/main/k8s/document_root_sslip.io/index.html
for HOST in {blocked,ns-gce,ns-hetzner,ns-ovh}.sslip.io; do
for HOST in {blocked,ns-gce,ns-hetzner,ns-ovh,ns-ovh-sg}.sslip.io; do
ssh $HOST curl -L -o /var/nginx/sslip.io/index.html https://raw.githubusercontent.com/cunnie/sslip.io/main/k8s/document_root_sslip.io/index.html
done
```

View File

@@ -14,7 +14,7 @@ Let's Encrypt DNS-01 challenge process.
Let's Encrypt will query your name servers for the TXT record
`_acme-challenge.xip.example.com`, then your DNS server will respond with the
TXT record _that should have been created on Route53 as part of the challenge_,
otherwise it'll return the delegated nameservers (ns-gce.sslip.io and so on).
otherwise it'll return the delegated nameservers (ns-ovh.sslip.io and so on).
### Using the sslip.io domain

View File

@@ -236,21 +236,22 @@ var _ = Describe("sslip.io-dns-server", func() {
digCmd = exec.Command("dig", strings.Split(digArgs, " ")...)
digSession, err = Start(digCmd, GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred())
Eventually(digSession).Should(Say(`104.155.144.4`))
Eventually(digSession).Should(Say(`5.78.115.44`))
Eventually(digSession).Should(Say(`51.75.53.19`))
Eventually(digSession).Should(Say(`51.79.178.89`))
Eventually(digSession, 1).Should(Exit(0))
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeA ns.sslip.io. \? 104.155.144.4, 5.78.115.44, 51.75.53.19\n`))
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeA ns.sslip.io. \? 5.78.115.44, 51.75.53.19, 51.79.178.89\n`))
})
It("returns all the AAAA records", func() {
digArgs = "@localhost aaaa ns.sslip.io +short -p " + strconv.Itoa(port)
digCmd = exec.Command("dig", strings.Split(digArgs, " ")...)
digSession, err = Start(digCmd, GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred())
Eventually(digSession).Should(Say(`2600:1900:4000:4d12::`))
Eventually(digSession).Should(Say(`2a01:4ff:1f0:c920::`))
Eventually(digSession).Should(Say(`2001:41d0:602:2313::1`))
Eventually(digSession).Should(Say(`2402:1f00:8001:d59::1`))
Eventually(digSession, 1).Should(Exit(0))
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeAAAA ns.sslip.io. \? 2600:1900:4000:4d12::, 2a01:4ff:1f0:c920::, 2001:41d0:602:2313::1\n`))
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeAAAA ns.sslip.io. \? 2a01:4ff:1f0:c920::, 2001:41d0:602:2313::1, 2402:1f00:8001:d59::1\n`))
})
})
When("there are multiple MX records returned (e.g. sslip.io)", func() {
@@ -274,18 +275,18 @@ var _ = Describe("sslip.io-dns-server", func() {
Eventually(digSession).Should(Say(`flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 6`))
Eventually(digSession).Should(Say(`;; ANSWER SECTION:`))
Eventually(digSession).Should(Say(`;; ADDITIONAL SECTION:`))
Eventually(digSession).Should(Say(`ns-gce.sslip.io..*104.155.144.4\n`))
Eventually(digSession).Should(Say(`ns-gce.sslip.io..*2600:1900:4000:4d12::\n`))
Eventually(digSession).Should(Say(`ns-hetzner.sslip.io..*5.78.115.44\n`))
Eventually(digSession).Should(Say(`ns-hetzner.sslip.io..*2a01:4ff:1f0:c920::\n`))
Eventually(digSession).Should(Say(`ns-ovh.sslip.io..*51.75.53.19\n`))
Eventually(digSession).Should(Say(`ns-ovh.sslip.io..*2001:41d0:602:2313::1\n`))
Eventually(digSession).Should(Say(`ns-ovh-sg.sslip.io..*51.79.178.89\n`))
Eventually(digSession).Should(Say(`ns-ovh-sg.sslip.io..*2402:1f00:8001:d59::1\n`))
Eventually(digSession, 1).Should(Exit(0))
// the server names may appear out-of-order
Eventually(string(digSession.Out.Contents())).Should(MatchRegexp(`NS\tns-gce.sslip.io.\n`))
Eventually(string(digSession.Out.Contents())).Should(MatchRegexp(`NS\tns-hetzner.sslip.io.\n`))
Eventually(string(digSession.Out.Contents())).Should(MatchRegexp(`NS\tns-ovh.sslip.io.\n`))
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeNS example.com. \? ns-gce.sslip.io., ns-hetzner.sslip.io., ns-ovh.sslip.io.\n`))
Eventually(string(digSession.Out.Contents())).Should(MatchRegexp(`NS\tns-ovh-sg.sslip.io.\n`))
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeNS example.com. \? ns-hetzner.sslip.io., ns-ovh.sslip.io., ns-ovh-sg.sslip.io.\n`))
})
})
When(`there are multiple TXT records returned (e.g. SPF for sslip.io)`, func() {
@@ -407,8 +408,8 @@ var _ = Describe("sslip.io-dns-server", func() {
// use regex to account for rotated nameserver order
Entry("an NS record with acme_challenge with a forbidden string is not delegated",
"@localhost _acme-challenge.raiffeisen.fe80--.sslip.io ns +short",
`\Ans-[a-z]+.sslip.io.\nns-[a-z]+.sslip.io.\nns-[a-z]+.sslip.io.\n\z`,
`TypeNS _acme-challenge.raiffeisen.fe80--.sslip.io. \? ns-gce.sslip.io., ns-hetzner.sslip.io., ns-ovh.sslip.io.\n$`),
`\Ans-[a-z-]+.sslip.io.\nns-[a-z-]+.sslip.io.\nns-[a-z-]+.sslip.io.\n\z`,
`TypeNS _acme-challenge.raiffeisen.fe80--.sslip.io. \? ns-hetzner.sslip.io., ns-ovh.sslip.io., ns-ovh-sg.sslip.io.\n$`),
Entry("an A record with a forbidden CIDR is redirected",
"@localhost nf.43.134.66.67.sslip.io +short",
`\A52.0.56.137\n\z`,

View File

@@ -141,26 +141,27 @@ src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]-->
</thead>
<tbody>
<tr class="odd">
<td><code>ns-gce.sslip.io.</code></td>
<td>104.155.144.4</td>
<td>USA</td>
</tr>
<tr class="even">
<td><code>ns-hetzner.sslip.io.</code></td>
<td>5.78.115.44<br>
2a01:4ff:1f0:c920::</td>
<td>USA</td>
</tr>
<tr class="odd">
<tr class="even">
<td><code>ns-ovh.sslip.io.</code></td>
<td>51.75.53.19<br>
2001:41d0:602:2313::1</td>
<td>Poland</td>
</tr>
<tr class="odd">
<td><code>ns-ovh-sg.sslip.io.</code></td>
<td>51.79.178.89<br>
2402:1f00:8001:d59::1</td>
<td>Singapore</td>
</tr>
</tbody>
</table>
<p>Lets test it from the command line using <code>dig</code>:</p>
<pre><code>dig @ns-gce.sslip.io. 169-254-169-254.xip.example.com +short</code></pre>
<pre><code>dig @ns-ovh.sslip.io. 169-254-169-254.xip.example.com +short</code></pre>
<p>Yields, hopefully: <sup><a href="#timeout" class="alert-link">[connection timed out]</a></sup></p>
<pre><code>169.254.169.254</code></pre>
<h3 id="server">But I Want My Own DNS Server!</h3>
@@ -171,7 +172,7 @@ src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]-->
our server within a docker container:</p>
<pre>
docker run -it --rm fedora
curl -L https://github.com/cunnie/sslip.io/releases/download/3.2.6/sslip.io-dns-server-linux-amd64 -o dns-server
curl -L https://github.com/cunnie/sslip.io/releases/download/3.2.7/sslip.io-dns-server-linux-amd64 -o dns-server
chmod +x dns-server
./dns-server 2&gt; dns-server.log &
dnf install -y bind-utils
@@ -250,7 +251,7 @@ dig @ns.sslip.io txt ip.sslip.io +short -6 # forces IPv6 lookup; sample reply "2
<h4 id="version">Determining The Server Version of Software</h4>You can determine the server version of the
sslip.io software by querying the TXT record of <code>version.status.sslip.io</code>:
<pre>
dig @ns-gce.nono.io version.status.sslip.io txt +short
dig @ns-ovh.nono.io version.status.sslip.io txt +short
"2.7.0"
"2023/10/04-18:51:49-0700"
"8f7f2df"
@@ -324,7 +325,7 @@ dig @ns-ovh.sslip.io metrics.status.sslip.io txt +short
<dd>The number of responses which included a delegation of the NS (name server) to satisfy a certificate
authority's DNS-01 challenge. This lookup is used for generating wildcard certificates from Let's Encrypt and
other certificate authority. Technically this is not a "successful" query in that we don't return a record in
the ANSWER section, but we do return an NS record in the AUTHORITY section. (e.g. "dig @ns-gce.sslip.io
the ANSWER section, but we do return an NS record in the AUTHORITY section. (e.g. "dig @ns-ovh.sslip.io
_acme-challenge.192.168.0.1.sslip.io. soa")</dd>
</dl>
<h3 id="related">Related Services</h3>

12
main.go
View File

@@ -17,25 +17,25 @@ func main() {
var blocklistURL = flag.String("blocklistURL",
"https://raw.githubusercontent.com/cunnie/sslip.io/main/etc/blocklist.txt",
`URL containing a list of non-resolvable IPs/names/CIDRs, usually phishing or scamming sites. Example "file://etc/blocklist.txt"`)
var nameservers = flag.String("nameservers", "ns-gce.sslip.io.,ns-hetzner.sslip.io.,ns-ovh.sslip.io.",
var nameservers = flag.String("nameservers", "ns-hetzner.sslip.io.,ns-ovh.sslip.io.,ns-ovh-sg.sslip.io.",
"comma-separated list of FQDNs of nameservers. If you're running your own sslip.io nameservers, set them here")
var addresses = flag.String("addresses",
"sslip.io=78.46.204.247,"+
"sslip.io=2a01:4f8:c17:b8f::2,"+
"ns.sslip.io=104.155.144.4,"+
"ns.sslip.io=2600:1900:4000:4d12::,"+
"ns.sslip.io=5.78.115.44,"+
"ns.sslip.io=2a01:4ff:1f0:c920::,"+
"ns.sslip.io=51.75.53.19,"+
"ns.sslip.io=2001:41d0:602:2313::1,"+
"ns.sslip.io=51.79.178.89,"+
"ns.sslip.io=2402:1f00:8001:d59::1,"+
"blocked.sslip.io=52.0.56.137,"+
"blocked.sslip.io=2600:1f18:aaf:6900::a,"+
"ns-gce.sslip.io=104.155.144.4,"+
"ns-gce.sslip.io=2600:1900:4000:4d12::,"+
"ns-hetzner.sslip.io=5.78.115.44,"+
"ns-hetzner.sslip.io=2a01:4ff:1f0:c920::,"+
"ns-ovh.sslip.io=51.75.53.19,"+
"ns-ovh.sslip.io=2001:41d0:602:2313::1",
"ns-ovh.sslip.io=2001:41d0:602:2313::1,"+
"ns-ovh-sg.sslip.io=51.79.178.89,"+
"ns-ovh-sg.sslip.io=2402:1f00:8001:d59::1",
"comma-separated list of hosts and corresponding IPv4 and/or IPv6 address(es). If you're running your own sslip.io nameservers, add their hostnames and addresses here. If unsure, add to the list rather than replace")
var delegates = flag.String("delegates", "", "comma-separated list of domains you own "+
"and nameservers you control to which to delegate, often used to acquire wildcard certificates from "+

View File

@@ -18,7 +18,7 @@ def get_whois_nameservers(domain)
end
domain = ENV['DOMAIN'] || 'example.com'
sslip_version = '3.2.6'
sslip_version = '3.2.7'
whois_nameservers = get_whois_nameservers(domain)
describe domain do

View File

@@ -79,14 +79,14 @@ var _ = Describe("Xip", func() {
Describe("NSResources()", func() {
When("we use the default nameservers", func() {
var x, _ = xip.NewXip("file:///", []string{"ns-gce.sslip.io.", "ns-hetzner.sslip.io.", "ns-ovh.sslip.io."}, []string{}, []string{})
var x, _ = xip.NewXip("file:///", []string{"ns-hetzner.sslip.io.", "ns-ovh.sslip.io.", "ns-ovh-sg.sslip.io."}, []string{}, []string{})
It("returns the name servers", func() {
randomDomain := testhelper.Random8ByteString() + ".com."
ns := x.NSResources(randomDomain)
Expect(len(ns)).To(Equal(3))
Expect(ns[0].NS.String()).To(Equal("ns-gce.sslip.io."))
Expect(ns[1].NS.String()).To(Equal("ns-hetzner.sslip.io."))
Expect(ns[2].NS.String()).To(Equal("ns-ovh.sslip.io."))
Expect(ns[0].NS.String()).To(Equal("ns-hetzner.sslip.io."))
Expect(ns[1].NS.String()).To(Equal("ns-ovh.sslip.io."))
Expect(ns[2].NS.String()).To(Equal("ns-ovh-sg.sslip.io."))
})
When(`the domain name contains "_acme-challenge."`, func() {
When("the domain name has an embedded IP", func() {
@@ -112,13 +112,13 @@ var _ = Describe("Xip", func() {
When("we delegate domains to other nameservers", func() {
When(`we don't use the "=" in the arguments`, func() {
It("returns an informative log message", func() {
var _, logs = xip.NewXip("file://etc/blocklist-test.txt", []string{"ns-gce.sslip.io.", "ns-hetzner.sslip.io.", "ns-ovh.sslip.io."}, []string{}, []string{"noEquals"})
var _, logs = xip.NewXip("file://etc/blocklist-test.txt", []string{"ns-hetzner.sslip.io.", "ns-ovh.sslip.io.", "ns-ovh-sg.sslip.io."}, []string{}, []string{"noEquals"})
Expect(strings.Join(logs, "")).To(MatchRegexp(`"-delegates: arguments should be in the format "delegatedDomain=nameserver", not "noEquals"`))
})
})
When(`there's no "." at the end of the delegated domain or nameserver`, func() {
It(`helpfully adds the "."`, func() {
var x, logs = xip.NewXip("file://etc/blocklist-test.txt", []string{"ns-gce.sslip.io.", "ns-hetzner.sslip.io.", "ns-ovh.sslip.io."}, []string{}, []string{"a=b"})
var x, logs = xip.NewXip("file://etc/blocklist-test.txt", []string{"ns-hetzner.sslip.io.", "ns-ovh.sslip.io.", "ns-ovh-sg.sslip.io."}, []string{}, []string{"a=b"})
Expect(strings.Join(logs, "")).To(MatchRegexp(`Adding delegated NS record "a\.=b\."`))
ns := x.NSResources("a.")
Expect(len(ns)).To(Equal(1))