Published: Oct 29, 2024 by Isaac Johnson
Today we will check out two interesting Open-Source monitor/trackers - WebCheck and Medama. We’ll also look at a great simple Open-source note/secret sharing app, Enclosed. Webcheck does have some additional features that are enabled with a GCP API key (which we’ll cover how to fetch).
Let’s start with Webcheck.
Webcheck
I became aware of Web Check from a MariusHosting Blog about hosting it on a NAS.
Let’s first start with a straightforward docker invokation
$ docker run -p 3000:3000 lissy93/web-check
Perhaps my internet is insufficent here
builder@LuiGi:~/Workspaces/jekyll-blog$ docker run -p 3000:3000 lissy93/web-check
Unable to find image 'lissy93/web-check:latest' locally
docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers).
See 'docker run --help'.
builder@LuiGi:~/Workspaces/jekyll-blog$ docker run -p 3000:3000 lissy93/web-check
Unable to find image 'lissy93/web-check:latest' locally
docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": context deadline exceeded.
See 'docker run --help'.
I tried to fetch from the Dockerhub location directly:
docker pull lissy93/web-check
Using default tag: latest
latest: Pulling from lissy93/web-check
3d53ef4019fc: Pull complete
08f0bf643eb6: Pull complete
6b037c2b46ab: Pull complete
6043113e1c69: Pull complete
3124fb5fe8cc: Pull complete
cf0c111ae42e: Pull complete
e2abac14e0ec: Pull complete
169d84d2ff1d: Pull complete
c2d8fef65aa0: Pull complete
9dbd70f50705: Pull complete
3201d69f0bd0: Pull complete
70bc80b8eff3: Pull complete
Digest: sha256:a2ae048b601c7d44ab148d746f5836ace7b4e8514ba8f905c4890b90635c62c5
Status: Downloaded newer image for lissy93/web-check:latest
docker.io/lissy93/web-check:latest
What's Next?
View a summary of image vulnerabilities and recommendations → docker scout quickview lissy93/web-check
I can now run it
builder@LuiGi:~/Workspaces/jekyll-blog$ !1999
docker run -p 3000:3000 lissy93/web-check
yarn run v1.22.19
$ node server
__ __ _ ___ _ _
\ \ / /__| |__ ___ / __| |_ ___ __| |__
\ \/\/ / -_) '_ \___| (__| ' \/ -_) _| / /
\_/\_/\___|_.__/ \___|_||_\___\__|_\_\
🚀 Web-Check is up and running at http://localhost:3000
🛟 For documentation and support, visit the GitHub repo: https://github.com/lissy93/web-check
💖 Found Web-Check useful? Consider sponsoring us on GitHub to help fund maintenance & development.
(node:29) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
I can then run a check against one of my hosted apps
Some of these “failed” checks are because it needs a Google API key
Let’s try creating a GCP API key to look at some of the additional quality checks
I can go to “APIs & Credentials” to create a new API key
I can then create a new key
I can relaunch with docker
$ docker run -e GOOGLE_CLOUD_API_KEY=AIzxxxxxxxxxxxxxxxxxxxxxxxxx -p 30
00:3000 lissy93/web-check
yarn run v1.22.19
$ node server
__ __ _ ___ _ _
\ \ / /__| |__ ___ / __| |_ ___ __| |__
\ \/\/ / -_) '_ \___| (__| ' \/ -_) _| / /
\_/\_/\___|_.__/ \___|_||_\___\__|_\_\
🚀 Web-Check is up and running at http://localhost:3000
🛟 For documentation and support, visit the GitHub repo: https://github.com/lissy93/web-check
💖 Found Web-Check useful? Consider sponsoring us on GitHub to help fund maintenance & development.
(node:29) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
This time, I got a lot more details
However, I dont really desire to run it on my laptop all the time, so let’s move this to a dockerhost instance instead.
builder@builder-T100:~$ docker run -d --name webcheck -e GOOGLE_CLOUD_API_KEY=AIzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -p 3020:3000 lissy93/web-check
Unable to find image 'lissy93/web-check:latest' locally
latest: Pulling from lissy93/web-check
3d53ef4019fc: Pull complete
08f0bf643eb6: Pull complete
6b037c2b46ab: Pull complete
6043113e1c69: Pull complete
3124fb5fe8cc: Pull complete
cf0c111ae42e: Pull complete
e2abac14e0ec: Pull complete
169d84d2ff1d: Pull complete
c2d8fef65aa0: Pull complete
9dbd70f50705: Pull complete
3201d69f0bd0: Pull complete
70bc80b8eff3: Pull complete
Digest: sha256:a2ae048b601c7d44ab148d746f5836ace7b4e8514ba8f905c4890b90635c62c5
Status: Downloaded newer image for lissy93/web-check:latest
0c8ca545e0359cda513f3babe845f5d26d435e270d682fdd630fdb2db6e76b6d
which works fine
Enclosed
Let’s start by firing up an instance on a docker host
builder@builder-T100:~$ docker run -d --name enclosed -e PORT=8713 -v /home/builder/enclosed:/app/.data -p 8
713:8713 corentinth/enclosed:latest
Unable to find image 'corentinth/enclosed:latest' locally
latest: Pulling from corentinth/enclosed
43c4264eed91: Already exists
4ddba3401738: Pull complete
d17475b571f3: Pull complete
f7c3aa8cb1f9: Pull complete
d728484bbda6: Pull complete
62ebd2eb3360: Pull complete
1bb1a2de862b: Pull complete
8f19f44523de: Pull complete
Digest: sha256:d57b54553c10195c6deee92ea07bee5b7dc20e2d45da7c3bc009c3dd3901c570
Status: Downloaded newer image for corentinth/enclosed:latest
07addf17dafcf8954bdfb46bc53221c0435e737798c699ca072e7d1aea571f80
I’ll now create a DNS record
$ az account set --subscription "Pay-As-You-Go" && az network dns record-set a add-record -g idjdnsrg -z tpk.pw -a 75.73.224.240 -n enclosed
{
"ARecords": [
{
"ipv4Address": "75.73.224.240"
}
],
"TTL": 3600,
"etag": "3451bd2b-173f-4651-814c-3304e4fe1f81",
"fqdn": "enclosed.tpk.pw.",
"id": "/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idjdnsrg/providers/Microsoft.Network/dnszones/tpk.pw/A/enclosed",
"name": "enclosed",
"provisioningState": "Succeeded",
"resourceGroup": "idjdnsrg",
"targetResource": {},
"trafficManagementProfile": {},
"type": "Microsoft.Network/dnszones/A"
}
Next I’ll create an Ingress, Service and Endpoint:
$ cat enclosed.ingress.yaml
---
apiVersion: v1
kind: Endpoints
metadata:
name: enclosed-external-ip
subsets:
- addresses:
- ip: 192.168.1.100
ports:
- name: enclosedint
port: 8713
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: enclosed-external-ip
spec:
clusterIP: None
clusterIPs:
- None
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
- IPv6
ipFamilyPolicy: RequireDualStack
ports:
- name: enclosed
port: 80
protocol: TCP
targetPort: 8713
sessionAffinity: None
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: azuredns-tpkpw
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.org/websocket-services: enclosed-external-ip
generation: 1
labels:
app.kubernetes.io/instance: enclosedingress
name: enclosedingress
spec:
rules:
- host: enclosed.tpk.pw
http:
paths:
- backend:
service:
name: enclosed-external-ip
port:
number: 80
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- enclosed.tpk.pw
secretName: enclosed-tls
$ kubectl apply -f enclosed.ingress.yaml
endpoints/enclosed-external-ip created
service/enclosed-external-ip created
ingress.networking.k8s.io/enclosedingress created
When the cert is satisified
$ kubectl get cert enclosed-tls
NAME READY SECRET AGE
enclosed-tls True enclosed-tls 113s
I could then directly access it
I’ll try creating a note with an hour expiry
I then see it created a URL and QR
And in an InPrivate window I could verify the link https://enclosed.tpk.pw/01jay091e5781nyydr8g0g27hw#H2hfBHIzc5zrvE6Xait3pGp2E9XETuL6UC4sxSshJZI
I can create another note with a password and autodelete policy
This time I get a warning that viewing it will delete it
I can then enter the password
That worked. I then just refreshed
Let’s see some examples
Medama
One more self-hosted monitor akin to WebCheck we can check out is Medama. This also ended up on my list from an older MariusHosting post.
From their Installation docs, we can start with the docker steps.
I’m going to use port 8484 as 8080 is already used locally
$ docker run -d -p 8484:8080 -v medama-data:/app/data ghcr.io/medama-io/medama:latest
Unable to find image 'ghcr.io/medama-io/medama:latest' locally
latest: Pulling from medama-io/medama
a85ce7502e1a: Pull complete
e8d9a567199d: Pull complete
058cf3d8c2ba: Pull complete
b6824ed73363: Pull complete
7c12895b777b: Pull complete
33e068de2649: Pull complete 5664b15f108b: Pull complete
27be814a09eb: Pull complete
4aa0ea1413d3: Pull complete
da7816fa955e: Pull complete
9aee425378d2: Pull complete
209150bce63e: Pull complete
903010886edf: Pull complete
c9bc90a4de9d: Pull complete
2b3410766942: Pull complete
911458164fa1: Pull complete
9e6437a0de2e: Pull complete
879a3318ec60: Pull complete
Digest: sha256:1761c0f9881a8b90b1bc9175518c6c50122ac26f2899d825bb7d9ffa0a48ff8f
Status: Downloaded newer image for ghcr.io/medama-io/medama:latest
7666782213f7c2eb4019463205a2d403892086b3be6a39f704d6a3d113731fc1
Our first login does show 500, but I’ll try the “Log In” button regardless
The default login is admin
with password CHANGE_ME_ON_FIRST_LOGIN
However, that did indeed just redirect to the landing page so something might be broken.
While there is nothing in the logs
$ docker logs 7666782213f7
{"level":"info","time":1729854439,"message":"Medama Analytics v0.5.1, commit=7f3ef9f"}
{"level":"warn","id":1,"name":"0001_sqlite_schema.go","type":"sqlite","time":1729854442,"message":"running migration, do not close the application"}
{"level":"info","id":1,"name":"0001_sqlite_schema.go","type":"sqlite","time":1729854442,"message":"migrated"}
{"level":"warn","id":6,"name":"0006_sqlite_settings.go","type":"sqlite","time":1729854442,"message":"running migration, do not close the application"}
{"level":"info","id":6,"name":"0006_sqlite_settings.go","type":"sqlite","time":1729854442,"message":"migrated"}
{"level":"warn","id":2,"name":"0002_duckdb_schema.go","type":"duckdb","time":1729854442,"message":"running migration, do not close the application"}
{"level":"info","id":2,"name":"0002_duckdb_schema.go","type":"duckdb","time":1729854442,"message":"migrated"}
{"level":"warn","id":3,"name":"0003_duckdb_referrer.go","type":"duckdb","time":1729854442,"message":"running migration, do not close the application"}
{"level":"info","id":3,"name":"0003_duckdb_referrer.go","type":"duckdb","time":1729854442,"message":"migrated"}
{"level":"warn","id":4,"name":"0004_duckdb_events.go","type":"duckdb","time":1729854442,"message":"running migration, do not close the application"}
{"level":"info","id":4,"name":"0004_duckdb_events.go","type":"duckdb","time":1729854442,"message":"migrated"}
{"level":"warn","id":5,"name":"0005_duckdb_event_bid.go","type":"duckdb","time":1729854442,"message":"running migration, do not close the application"}
{"level":"info","id":5,"name":"0005_duckdb_event_bid.go","type":"duckdb","time":1729854442,"message":"migrated"}
{"level":"warn","time":1729854442,"message":"no users found, creating default admin user"}
{"level":"warn","time":1729854442,"message":"default admin user created"}
{"level":"info","time":1729854442,"message":"Starting server at http://localhost:8080"}
I suspect it’s because I failed to create that medama-data volume when i launched.
I’ll stop and rm the existing instance (frosty_mcclintock), create the docker volume and re-launch
$ docker stop frosty_mcclintock
frosty_mcclintock
$ docker rm frosty_mcclintock
frosty_mcclintock
$ docker volume create medama-data
medama-data
$ docker run -d -p 8484:8080 -v medama-data:/app/data ghcr.io/medama-io/medama:latest
663ea8ae503916c0b3cfbec204f7766772ab6b6552974a7c4f1ccb53d3b43d14
This time I see a different login page
But I still see an error
I’m going to rule out Windows/WSL and move to my proper Dockerhost
builder@builder-T100:~$ mkdir medama
builder@builder-T100:~$ mkdir medama/data
builder@builder-T100:~$ docker run -d --name medama -v /home/builder/medama/data:/app/data -p 8484:8080 ghcr.io/medama-io/medama:latest
Unable to find image 'ghcr.io/medama-io/medama:latest' locally
latest: Pulling from medama-io/medama
a85ce7502e1a: Pull complete
e8d9a567199d: Pull complete
058cf3d8c2ba: Pull complete
b6824ed73363: Pull complete
7c12895b777b: Pull complete
33e068de2649: Pull complete
5664b15f108b: Pull complete
27be814a09eb: Pull complete
4aa0ea1413d3: Pull complete
da7816fa955e: Pull complete
9aee425378d2: Pull complete
209150bce63e: Pull complete
903010886edf: Pull complete
c9bc90a4de9d: Pull complete
2b3410766942: Pull complete
911458164fa1: Pull complete
9e6437a0de2e: Pull complete
879a3318ec60: Pull complete
Digest: sha256:1761c0f9881a8b90b1bc9175518c6c50122ac26f2899d825bb7d9ffa0a48ff8f
Status: Downloaded newer image for ghcr.io/medama-io/medama:latest
This time the login goes nowhere and I can see some errors in the logs
$ docker logs medama
{"level":"info","time":1729855146,"message":"Medama Analytics v0.5.1, commit=7f3ef9f"}
{"level":"warn","id":1,"name":"0001_sqlite_schema.go","type":"sqlite","time":1729855149,"message":"running migration, do not close the application"}
{"level":"info","id":1,"name":"0001_sqlite_schema.go","type":"sqlite","time":1729855149,"message":"migrated"}
{"level":"warn","id":6,"name":"0006_sqlite_settings.go","type":"sqlite","time":1729855149,"message":"running migration, do not close the application"}
{"level":"info","id":6,"name":"0006_sqlite_settings.go","type":"sqlite","time":1729855149,"message":"migrated"}
{"level":"warn","id":2,"name":"0002_duckdb_schema.go","type":"duckdb","time":1729855149,"message":"running migration, do not close the application"}
{"level":"info","id":2,"name":"0002_duckdb_schema.go","type":"duckdb","time":1729855149,"message":"migrated"}
{"level":"warn","id":3,"name":"0003_duckdb_referrer.go","type":"duckdb","time":1729855149,"message":"running migration, do not close the application"}
{"level":"info","id":3,"name":"0003_duckdb_referrer.go","type":"duckdb","time":1729855149,"message":"migrated"}
{"level":"warn","id":4,"name":"0004_duckdb_events.go","type":"duckdb","time":1729855149,"message":"running migration, do not close the application"}
{"level":"info","id":4,"name":"0004_duckdb_events.go","type":"duckdb","time":1729855149,"message":"migrated"}
{"level":"warn","id":5,"name":"0005_duckdb_event_bid.go","type":"duckdb","time":1729855149,"message":"running migration, do not close the application"}
{"level":"info","id":5,"name":"0005_duckdb_event_bid.go","type":"duckdb","time":1729855149,"message":"migrated"}
{"level":"warn","time":1729855149,"message":"no users found, creating default admin user"}
{"level":"warn","time":1729855149,"message":"default admin user created"}
{"level":"info","time":1729855149,"message":"Starting server at http://localhost:8080"}
{"level":"warn","path":"/websites","method":"GET","status_code":401,"message":"operation GetWebsites: security '': security requirement is not satisfied","Connection":"keep-alive","Content-Type":"application/json","Content-Length":"","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36","time":1729855202,"message":"unauthorised"}
{"level":"info","operation":"PostAuthLogin","operationId":"post-auth-login","method":"POST","path":"/auth/login","duration":71.26452,"time":1729855212,"message":"success"}
{"level":"warn","path":"/websites","method":"GET","status_code":401,"message":"operation GetWebsites: security '': security requirement is not satisfied","Connection":"keep-alive","Content-Type":"application/json","Content-Length":"","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36","time":1729855212,"message":"unauthorised"}
{"level":"info","operation":"PostAuthLogin","operationId":"post-auth-login","method":"POST","path":"/auth/login","duration":49.082554,"time":1729855222,"message":"success"}
{"level":"warn","path":"/websites","method":"GET","status_code":401,"message":"operation GetWebsites: security '': security requirement is not satisfied","Connection":"keep-alive","Content-Type":"application/json","Content-Length":"","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36","time":1729855222,"message":"unauthorised"}
{"level":"info","operation":"PostAuthLogin","operationId":"post-auth-login","method":"POST","path":"/auth/login","duration":102.11171,"time":1729855240,"message":"success"}
{"level":"warn","path":"/websites","method":"GET","status_code":401,"message":"operation GetWebsites: security '': security requirement is not satisfied","Connection":"keep-alive","Content-Type":"application/json","Content-Length":"","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36","time":1729855240,"message":"unauthorised"}
{"level":"info","operation":"PostAuthLogin","operationId":"post-auth-login","method":"POST","path":"/auth/login","duration":45.680127,"time":1729855270,"message":"success"}
{"level":"warn","path":"/websites","method":"GET","status_code":401,"message":"operation GetWebsites: security '': security requirement is not satisfied","Connection":"keep-alive","Content-Type":"application/json","Content-Length":"","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0","time":1729855270,"message":"unauthorised"}
This isn’t helping. Even setting Allowed Origins to “*” fails
builder@builder-T100:~$ docker stop medama
medama
builder@builder-T100:~$ docker rm medama
medama
builder@builder-T100:~$ docker run -d --name medama -v /home/builder/medama/data:/app/data -e CORS_ALLOWED_ORIGINS=* -p 8484:8080 ghcr.io/medama-io/medama:latest
2e65eca238e74f9c203aefa08f1d16e2c088e8c39343a8871e46cd4c9a7b3a15
builder@builder-T100:~$ docker logs medama
{"level":"info","time":1729855548,"message":"Medama Analytics v0.5.1, commit=7f3ef9f"}
{"level":"info","time":1729855551,"message":"Starting server at http://localhost:8080"}
{"level":"info","operation":"PostAuthLogin","operationId":"post-auth-login","method":"POST","path":"/auth/login","duration":53.990618,"time":1729855552,"message":"success"}
{"level":"warn","path":"/websites","method":"GET","status_code":401,"message":"operation GetWebsites: security '': security requirement is not satisfied","Connection":"keep-alive","Content-Type":"application/json","Content-Length":"","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0","time":1729855552,"message":"unauthorised"}
{"level":"info","operation":"PostAuthLogin","operationId":"post-auth-login","method":"POST","path":"/auth/login","duration":76.317719,"time":1729855564,"message":"success"}
{"level":"warn","path":"/websites","method":"GET","status_code":401,"message":"operation GetWebsites: security '': security requirement is not satisfied","Connection":"keep-alive","Content-Type":"application/json","Content-Length":"","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0","time":1729855564,"message":"unauthorised"}
Actually it took a lot of trial and error - but it does need a volume. And more-over, it really must use port 8080 or you get that 500 error.
Here I launched back in WSL (since my Dockerhost already allocated 8080)
builder@DESKTOP-QADGF36:~$ docker run -d --name medama -v medama-data:/app/data -p 8080:8080 ghcr.io/medama-io/medama:latest
266ddb29271c97e283062c3ba3b62f08dc4cb4deb92deec75f48b0bcd6e6af0b
Even though I’m running locally, I’ll still practice setting the admin password to something other than default
Next, let’s add a site
I’ll add my own
So far I just see a dashboard with no data
Seems this backend assume we have already added the tracker as documented here.
So this assumes I expose Medama somehow to my website and embed a javascript tracker
<script defer src="https://[where-your-script-is-hosted].com/script.js" data-api="[different-analytics-server].com/api/" data-hash></script>
Which I can verify is there in the site
I want to test before I ever release into the wild
builder@DESKTOP-QADGF36:~$ vi testsite.html
builder@DESKTOP-QADGF36:~$ cat testsite.html
<HTML>
<HEAD>
<TITLE>Test Site</TITLE>
</HEAD>
<BODY>
<h1>test local stie</h1>
<script defer src="http://127.0.0.1/script.js" data-api="127.0.0.1/api/" data-hash></script>
</BODY>
</HTML>
I fired it up but don’t see any data (granted it’s not ‘freshbrewed.science’)
But I thought at least I would see something here
Since this is a bit hung-up, in my testing, with using port 8080, I’ll try pivoting to a Kubernetes deployment
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: medama-data-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: medama-deployment
spec:
replicas: 1
selector:
matchLabels:
app: medama
template:
metadata:
labels:
app: medama
spec:
volumes:
- name: medama-data
persistentVolumeClaim:
claimName: medama-data-pvc
containers:
- name: medama
image: ghcr.io/medama-io/medama:latest
ports:
- containerPort: 8080
volumeMounts:
- mountPath: /app/data
name: medama-data
---
apiVersion: v1
kind: Service
metadata:
name: medama-service
spec:
selector:
app: medama
ports:
- protocol: TCP
port: 80
targetPort: 8080
The apply it
$ kubectl apply -f ./medama.install.yaml
persistentvolumeclaim/medama-data-pvc created
deployment.apps/medama-deployment created
service/medama-service created
However, here we are stuck again in that it is really hung-up on 8080
$ kubectl port-forward svc/medama-service 8484:80
Forwarding from 127.0.0.1:8484 -> 8080
Forwarding from [::1]:8484 -> 8080
Handling connection for 8484
Handling connection for 8484
Just to do the test all the way, I’ll try creating a GCP CloudDNS record
$ gcloud dns --project=myanthosproject2 record-sets create medama.steeped.space --zone="steepedspace" --type="A" --ttl="300" --rrdatas="75.73.224.240"
NAME TYPE TTL DATA
medama.steeped.space. A 300 75.73.224.240
Then expose an ingress
$ cat ./medama.ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: gcpleprod2
ingress.kubernetes.io/proxy-body-size: "0"
ingress.kubernetes.io/ssl-redirect: "true"
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.org/client-max-body-size: "0"
nginx.org/proxy-connect-timeout: "3600"
nginx.org/proxy-read-timeout: "3600"
nginx.org/websocket-services: medama-service
name: medamagcpingress
spec:
rules:
- host: medama.steeped.space
http:
paths:
- backend:
service:
name: medama-service
port:
number: 80
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- medama.steeped.space
secretName: medamagcp-tls
$ kubectl apply -f ./medama.ingress.yaml
ingress.networking.k8s.io/medamagcpingress created
When I saw the cert satisified
$ kubectl get cert medamagcp-tls
NAME READY SECRET AGE
medamagcp-tls True medamagcp-tls 111s
I tried the URL (expecting failure). But this time it worked
This time the tracker page shows the right URL
The line we’ll need to embed:
<script defer src="https://medama.steeped.space/script.js"></script>
I’ll add our site
To test, I’ll add a line to my existing index page, though in reality this is generated with each release so this is just a fast-n-dirty way to test
builder@DESKTOP-QADGF36:~$ aws s3 cp s3://freshbrewed.science/index.html fbs.index.html
download: s3://freshbrewed.science/index.html to ./fbs.index.html
builder@DESKTOP-QADGF36:~$ aws s3 cp s3://freshbrewed.science/index.html fbs.index.html.bak
download: s3://freshbrewed.science/index.html to ./fbs.index.html.bak
builder@DESKTOP-QADGF36:~$ vi fbs.index.html
builder@DESKTOP-QADGF36:~$ diff -C 3 fbs.index.html.bak fbs.index.html
*** fbs.index.html.bak 2024-10-24 03:14:00.000000000 -0500
--- fbs.index.html 2024-10-25 07:01:59.385633091 -0500
***************
*** 29,34 ****
--- 29,35 ----
</head>
<body>
+ <script defer src="https://medama.steeped.space/script.js"></script>
<div class="navbar is-white">
<div class="container">
<div class="navbar-brand">
I can then copy it out there and create a CF Invalidation (using a CDN means i need to invalidate to make it actually go live quicker)
$ aws s3 cp ./fbs.index.html s3://freshbrewed.science/index.html --acl public-read
upload: ./fbs.index.html to s3://freshbrewed.science/index.html
$ aws cloudfront create-invalidation --distribution-id E3U2HCN2ZRTBZN --paths "/index.html"
{
"Location": "https://cloudfront.amazonaws.com/2019-03-26/distribution/E3U2HCN2ZRTBZN/invalidation/ID0IKH8FFE94GTUOVMGNLF33WM",
"Invalidation": {
"Id": "ID0IKH8FFE94GTUOVMGNLF33WM",
"Status": "InProgress",
"CreateTime": "2024-10-25T12:04:48.813Z",
"InvalidationBatch": {
"Paths": {
"Quantity": 1,
"Items": [
"/index.html"
]
},
"CallerReference": "cli-1729857885-67775"
}
}
}
I did a refresh and right away I saw some data
I plan to let it run today and see what it shows…
After a few days - and mind you this is just the main page and likely for browsers that don’t block javascript, I saw a few views
Compared to CloudFront (which will count all the pages)
Since 3000 and 7 is a pretty wide gap, I figured I would look to data usage to clarify what is real
While we can agree the data is limited, from what I can tell these folks must have just bookmarked this site as there is no defined referrer
Summary
Today we looked at WebCheck, a nice containerized app for checking everything from SSL checks to security vulnrabities to HTTP checks. It really covers a lot, especially when we tie in our GCP Cloud API key.
We looked at enclosed, which I’ve left running on enclosed.tpk.pw. I find this to be a very handy and useful secret sharing app. The fact it allows attachments spooks me a bit since that could be abused. But still, if I need to securely share a PEM key or a private SSL key, this would be an excellent way to do it. Though with any secret sharing tool, the only real way to trust it is to build and host it yourself.
Lastly, we looked at Medama, a simple but functional open-source website tracker. I’m not sure what the requirements are but it did seem to show a lower number of visitors. I could see it useful as a self-contained self-hosted solution.
Of the three, I’ll likely continue to use Enclosed as I really like it. I don’t like getting tracked so I tend to not use trackers for things. The stats I get from AWS are usually sufficient for most metrics. Also, the main page is likely the least used as I tend to just post to Mastodon and LinkedIn direct links to articles.