add goatcounter tracking to all sites via nginx sub_filter
Deploy nginx / deploy (push) Successful in 4s
Deploy nginx / deploy (push) Successful in 4s
This commit is contained in:
@@ -133,6 +133,19 @@ If any secret is missing, deploy fails with an error (not a warning).
|
|||||||
- **One domain per conf file** — `deploy.sh` derives the cert name from the
|
- **One domain per conf file** — `deploy.sh` derives the cert name from the
|
||||||
filename and collects all `server_name` values for that cert
|
filename and collects all `server_name` values for that cert
|
||||||
|
|
||||||
|
## GoatCounter (analytics)
|
||||||
|
|
||||||
|
GoatCounter runs at `goatcounter.hantim.net` for privacy-friendly web analytics.
|
||||||
|
|
||||||
|
**Script injection:** nginx injects the GoatCounter tracking script into all
|
||||||
|
HTML responses via `sub_filter`. The shared include `conf.d/goatcounter.inc`
|
||||||
|
is added to each site's main HTTPS server block. New sites get it automatically
|
||||||
|
via `app.sh`.
|
||||||
|
|
||||||
|
**Config:** `docker/goatcounter/compose.yaml` uses the `baethon/goatcounter`
|
||||||
|
image. Password is stored in Bitwarden (`hantim-goatcounter-password`) and
|
||||||
|
injected via the `.env.keys` mechanism.
|
||||||
|
|
||||||
## URL routing
|
## URL routing
|
||||||
|
|
||||||
- All HTTP → HTTPS redirect
|
- All HTTP → HTTPS redirect
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ for technical deep-dives, USECASES.md for expected behaviors.
|
|||||||
- `tools/remove-app.sh` -- Remove a static site (local files + Gitea repo)
|
- `tools/remove-app.sh` -- Remove a static site (local files + Gitea repo)
|
||||||
- `docker/nginx/conf.d/` -- Per-app nginx server blocks
|
- `docker/nginx/conf.d/` -- Per-app nginx server blocks
|
||||||
- `docker/<domain>/compose.yml` -- Per-app compose files
|
- `docker/<domain>/compose.yml` -- Per-app compose files
|
||||||
|
- `docker/goatcounter/` -- GoatCounter analytics (compose.yaml, .env.keys)
|
||||||
- `docker/garage/` -- Garage S3 object storage (Dockerfile, garage.toml, .env.keys)
|
- `docker/garage/` -- Garage S3 object storage (Dockerfile, garage.toml, .env.keys)
|
||||||
- `.gitea/workflows/` -- Per-app deploy workflows + provision.yml
|
- `.gitea/workflows/` -- Per-app deploy workflows + provision.yml
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ docker/
|
|||||||
compose.yml
|
compose.yml
|
||||||
<domain>/ # Per-app compose files (e.g. example.com)
|
<domain>/ # Per-app compose files (e.g. example.com)
|
||||||
compose.yml
|
compose.yml
|
||||||
|
goatcounter/ # GoatCounter analytics
|
||||||
garage/ # Garage S3-compatible object storage
|
garage/ # Garage S3-compatible object storage
|
||||||
compose.yml
|
compose.yml
|
||||||
Dockerfile
|
Dockerfile
|
||||||
@@ -195,6 +196,7 @@ Project: `hantim`. Fetched via `bws` CLI on the server.
|
|||||||
| `hantim-garage-media-key-id` | S3 access key ID for media uploads | `app.sh`, `aws` CLI |
|
| `hantim-garage-media-key-id` | S3 access key ID for media uploads | `app.sh`, `aws` CLI |
|
||||||
| `hantim-garage-media-secret-key` | S3 secret key for media uploads | `aws` CLI |
|
| `hantim-garage-media-secret-key` | S3 secret key for media uploads | `aws` CLI |
|
||||||
| `hantim-uptimerobot-api-key` | UptimeRobot API key for monitors | `app.sh` |
|
| `hantim-uptimerobot-api-key` | UptimeRobot API key for monitors | `app.sh` |
|
||||||
|
| `hantim-goatcounter-password` | GoatCounter admin password | `deploy.sh` |
|
||||||
|
|
||||||
Machine accounts: `hantim-server` (token at `/etc/bws-token`), `hantim-ci` (reserved).
|
Machine accounts: `hantim-server` (token at `/etc/bws-token`), `hantim-ci` (reserved).
|
||||||
|
|
||||||
|
|||||||
+12
-2
@@ -102,7 +102,17 @@ for stateless static sites.
|
|||||||
- SSL cert issued for `<name>.hantim.net` (no www variant)
|
- SSL cert issued for `<name>.hantim.net` (no www variant)
|
||||||
- Service ready for customization (edit compose.yml image, add `.env.keys` if needed)
|
- Service ready for customization (edit compose.yml image, add `.env.keys` if needed)
|
||||||
|
|
||||||
## 9. Upload media files
|
## 9. Analytics tracking
|
||||||
|
|
||||||
|
**Trigger:** automatic — nginx injects the GoatCounter script into all HTML responses.
|
||||||
|
|
||||||
|
**Expected outcome:**
|
||||||
|
- Every site includes the GoatCounter tracking script (injected via `sub_filter`)
|
||||||
|
- Page views are recorded at `goatcounter.hantim.net`
|
||||||
|
- New sites provisioned with `app.sh` include tracking automatically
|
||||||
|
- GoatCounter dashboard itself is not tracked
|
||||||
|
|
||||||
|
## 10. Upload media files
|
||||||
|
|
||||||
**Trigger:** `aws s3 cp` or `aws s3 sync` to `s3://example.com/`, or `./media.sh push` from a site repo.
|
**Trigger:** `aws s3 cp` or `aws s3 sync` to `s3://example.com/`, or `./media.sh push` from a site repo.
|
||||||
|
|
||||||
@@ -111,7 +121,7 @@ for stateless static sites.
|
|||||||
- Replicated to both Garage nodes (hantim + argento)
|
- Replicated to both Garage nodes (hantim + argento)
|
||||||
- Accessible at `https://www.example.com/media/<path>`
|
- Accessible at `https://www.example.com/media/<path>`
|
||||||
|
|
||||||
## 10. Local development with media files
|
## 11. Local development with media files
|
||||||
|
|
||||||
**Trigger:** `./media.sh pull` from a site repo.
|
**Trigger:** `./media.sh pull` from a site repo.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
sub_filter '</body>' '<script data-goatcounter="https://goatcounter.hantim.net/count" async src="//goatcounter.hantim.net/count.js"></script></body>';
|
||||||
|
sub_filter_once on;
|
||||||
|
sub_filter_types text/html;
|
||||||
@@ -37,6 +37,7 @@ server {
|
|||||||
ssl_certificate_key /etc/letsencrypt/live/haanmind.net/privkey.pem;
|
ssl_certificate_key /etc/letsencrypt/live/haanmind.net/privkey.pem;
|
||||||
|
|
||||||
include /etc/nginx/conf.d/security-headers.inc;
|
include /etc/nginx/conf.d/security-headers.inc;
|
||||||
|
include /etc/nginx/conf.d/goatcounter.inc;
|
||||||
|
|
||||||
location /media/ {
|
location /media/ {
|
||||||
proxy_pass http://garage:3902/;
|
proxy_pass http://garage:3902/;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ server {
|
|||||||
ssl_certificate_key /etc/letsencrypt/live/hantim.net/privkey.pem;
|
ssl_certificate_key /etc/letsencrypt/live/hantim.net/privkey.pem;
|
||||||
|
|
||||||
include /etc/nginx/conf.d/security-headers.inc;
|
include /etc/nginx/conf.d/security-headers.inc;
|
||||||
|
include /etc/nginx/conf.d/goatcounter.inc;
|
||||||
|
|
||||||
location /media/ {
|
location /media/ {
|
||||||
proxy_pass http://garage:3902/;
|
proxy_pass http://garage:3902/;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ server {
|
|||||||
ssl_certificate_key /etc/letsencrypt/live/hcsuzuki.music/privkey.pem;
|
ssl_certificate_key /etc/letsencrypt/live/hcsuzuki.music/privkey.pem;
|
||||||
|
|
||||||
include /etc/nginx/conf.d/security-headers.inc;
|
include /etc/nginx/conf.d/security-headers.inc;
|
||||||
|
include /etc/nginx/conf.d/goatcounter.inc;
|
||||||
|
|
||||||
location /media/ {
|
location /media/ {
|
||||||
proxy_pass http://garage:3902/;
|
proxy_pass http://garage:3902/;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ server {
|
|||||||
ssl_certificate_key /etc/letsencrypt/live/hcsuzuki.net/privkey.pem;
|
ssl_certificate_key /etc/letsencrypt/live/hcsuzuki.net/privkey.pem;
|
||||||
|
|
||||||
include /etc/nginx/conf.d/security-headers.inc;
|
include /etc/nginx/conf.d/security-headers.inc;
|
||||||
|
include /etc/nginx/conf.d/goatcounter.inc;
|
||||||
|
|
||||||
location /media/ {
|
location /media/ {
|
||||||
proxy_pass http://garage:3902/;
|
proxy_pass http://garage:3902/;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ server {
|
|||||||
ssl_certificate_key /etc/letsencrypt/live/thekims.family/privkey.pem;
|
ssl_certificate_key /etc/letsencrypt/live/thekims.family/privkey.pem;
|
||||||
|
|
||||||
include /etc/nginx/conf.d/security-headers.inc;
|
include /etc/nginx/conf.d/security-headers.inc;
|
||||||
|
include /etc/nginx/conf.d/goatcounter.inc;
|
||||||
|
|
||||||
location /media/ {
|
location /media/ {
|
||||||
proxy_pass http://garage:3902/;
|
proxy_pass http://garage:3902/;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ server {
|
|||||||
ssl_certificate_key /etc/letsencrypt/live/timothykim.net/privkey.pem;
|
ssl_certificate_key /etc/letsencrypt/live/timothykim.net/privkey.pem;
|
||||||
|
|
||||||
include /etc/nginx/conf.d/security-headers.inc;
|
include /etc/nginx/conf.d/security-headers.inc;
|
||||||
|
include /etc/nginx/conf.d/goatcounter.inc;
|
||||||
|
|
||||||
location /media/ {
|
location /media/ {
|
||||||
proxy_pass http://garage:3902/;
|
proxy_pass http://garage:3902/;
|
||||||
|
|||||||
@@ -356,6 +356,7 @@ server {
|
|||||||
ssl_certificate_key /etc/letsencrypt/live/$APP/privkey.pem;
|
ssl_certificate_key /etc/letsencrypt/live/$APP/privkey.pem;
|
||||||
|
|
||||||
include /etc/nginx/conf.d/security-headers.inc;
|
include /etc/nginx/conf.d/security-headers.inc;
|
||||||
|
include /etc/nginx/conf.d/goatcounter.inc;
|
||||||
|
|
||||||
location /media/ {
|
location /media/ {
|
||||||
proxy_pass http://garage:3902/;
|
proxy_pass http://garage:3902/;
|
||||||
|
|||||||
Reference in New Issue
Block a user