Author SHA1 Message Date
ahmza f402556380 Fix audit findings: bugs, security, perf, content
Bugs:
- setup-wsl: fix broken /img/WSL/* image paths (now bundle-relative;
  images were broken on the published post) + better alt text
- pi-docker-swarm: remove broken missing cluster.webp reference
- archetypes/posts.md: fix malformed {{ }} template so 'hugo new' works
- rename arrstack/arrstack.md -> index.md so it's a proper leaf bundle
- static/admin/config.yml: fix 'htpps' -> 'https' site_url typo
- fix silently-dropped <placeholder> text (unsafe=false dropped them):
  wrap <distro>/<username>/<user>/<version>/<ip address> etc in backticks
  across setup-wsl, securing-ssh, pi-docker-swarm, mc-server-on-docker

Security:
- render-link.html: add rel=noopener noreferrer to external target=_blank
- extend-footer.html: fix rel='me' trapped in class attr (broke Mastodon
  verification); add proper rel/target
- static/admin/index.html: pin Sveltia CMS to 0.172.4 via jsDelivr + SRI

Performance:
- hugo.toml: ignoreFiles for *.aseprite/*.bak (stop shipping source art;
  non-page files 23 -> 13)
- video shortcode: preload=metadata; image shortcode: loading=lazy decoding=async
- sws.toml: drop SPA page-fallback so missing paths return real 404 (404.html)

Content/SEO:
- normalize tag casing (HomeLab/RemoteAccess/SSH/HUGO -> lowercase),
  fix 'prodcutivity' typo, arrstack tags:[""] -> [], add welcome description
- delete stray index.md.bak
2026-07-25 03:36:50 +01:00
20 changed files with 51 additions and 432 deletions
-59
View File
@@ -1,59 +0,0 @@
# Caddyfile for the blog behind Cloudflare.
#
# Topology: Cloudflare (terminates TLS) -> Caddy (HTTP :80) -> SWS (blog:80)
#
# Cloudflare handles the public HTTPS cert, so Caddy serves plain HTTP on :80
# and does NOT need the Cloudflare DNS-01 / automatic-HTTPS setup. Set the
# Cloudflare SSL/TLS mode to "Full" so CF->origin is encrypted at the network
# layer (e.g. over your tunnel/Netbird), even though this listener is HTTP.
#
# Copy this file to /etc/caddy/Caddyfile on the caddy_cf host and reload:
# docker exec caddy_cf caddy reload --config /etc/caddy/Caddyfile
# or restart the container.
{
# Trust only Cloudflare's edge IPs so real visitor IPs (Cf-Connecting-Ip /
# X-Forwarded-For) are honoured only when the request actually comes from
# Cloudflare. This prevents header spoofing from any other source.
#
# The `cloudflare` IP source (WeidiDeng/caddy-cloudflare-ip, baked into the
# caddy-cf image) auto-fetches the ranges from cloudflare.com/ips-v4 and
# /ips-v6 and refreshes them periodically, so there's no static list to
# keep in sync.
servers {
trusted_proxies cloudflare {
interval 12h
timeout 15s
}
# Read the real visitor IP from these headers (only honoured for
# requests from trusted_proxies above). Cf-Connecting-Ip is
# Cloudflare's single authoritative end-user IP; X-Forwarded-For is
# the fallback if a request ever arrives without the CF header.
client_ip_headers Cf-Connecting-Ip X-Forwarded-For
}
}
# Bind to the hostname on the HTTP port only. Because the address has an
# explicit ":80" scheme/port, Caddy will NOT try to provision a TLS cert.
http://blog.ahmza.com {
# THE responder: proxy every request to the blog (SWS) container.
# This is what was missing before (requests fell through to a NOP -> blank page).
reverse_proxy blog:80
# Compression happens here (SWS has it disabled on purpose).
encode zstd gzip
# Security headers (single source of truth; SWS has security-headers off).
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
# Drop Caddy's default Server header.
-Server
}
log {
output stdout
format console
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
---
title: {{ replace .TranslationBaseName "-" " " | title }}
description: ""
tags: [""]
tags: []
author: "ahmza"
date: {{ .Date }}
draft: true
+5
View File
@@ -14,6 +14,11 @@ pagination.pagerSize = 10
buildDrafts = false
buildFuture = false
# Keep source-art and editor backup files out of the built site. Without this,
# files inside page bundles (e.g. feature.aseprite) are copied into public/ as
# page resources and served publicly.
ignoreFiles = ['\.aseprite$', '\.bak$']
enableEmoji = true
# googleAnalytics = "G-XXXXXXXXX"
@@ -1,7 +1,7 @@
---
title: Arrstack
description:
tags: [""]
tags: []
author: "ahmza"
date: 2025-05-09T23:44:27+01:00
draft: true
@@ -4,7 +4,7 @@ description: In the modern age we are overwhelmed with stimuli. Learn to cut out
tags:
- lifestyle
- minimalism
- prodcutivity
- productivity
author: ahmza
date: 2024-01-02
draft: false
+2 -2
View File
@@ -185,8 +185,8 @@ cd .server-data
2. **Download a Minecraft server jar file:**
- [Vanilla Minecraft Server](https://www.minecraft.net/en-us/download/server)
- Right-click the green link that says minecraft_server.<version>.jar and copy the link address.
- Download with: curl -o server.jar <link you copied here>
- Right-click the green link that says `minecraft_server.<version>.jar` and copy the link address.
- Download with: `curl -o server.jar <link you copied here>`
- [Fabric Mod loader server](https://fabricmc.net/use/server/)
- Select the Minecraft version, Fabric Loader Version, and the Installer Version of your choice. I tend to go with the latest.
- Download with: Copy the curl command under CLI download
@@ -1,243 +0,0 @@
---
title: Minecraft Server on Docker ⛏ 🐳
date: 2022-05-24
lastmod: 2024-07-20
author: "ahmza"
draft: false
weight:
tags: ["games", "docker"]
description: "Ever wanted to build a Minecraft server in docker !! Start here"
---
## **Introduction**
Minecraft is a great game that becomes even more enjoyable when played with
friends. One of the best ways to do this is by setting up a dedicated server.
This guide will help you do just that!
Setting up and running a Minecraft server does not require a lot of resources,
but based on my experience, allocating more resources significantly enhances
performance. Especially when you start to add mods and increase player count.
## **Prerequisites**
- Docker
- Docker Compose
See [Pi Cluster](/posts/pi-docker-swarm/)
for more information about my docker setup.
## **Requirements**
_Requirements Gathered from [here](https://minecraft.fandom.com/wiki/Server/Requirements/Dedicated#Unix_.28Linux.2C_BSD.2C_macOS.29)_
### **Minimum (1-5 Players)**
- Intel Pentium 4 or AMD Athlon based CPU
- 512 MB RAM
- 2 GB Storage space
### **Recommended (10-15 Players)**
- Intel Core or AMD K8 based CPU
- 3 GB RAM
- 16 GB Storage Space
### **Optimal (20+ Players)**
- Intel i5/i7 or AMD Ryzen 5/7 Based CPU
- 6 GB RAM
- 35 GB Storage Space
**My opinion**:
I personally went with the **optimal** settings as I wanted to run mods as well
as have the capacity for ~10 players. This gives the server breathing room.
However if you will be runing no mods or a few light weight mods and only a few
players then there really is no need to go higher than 3-4 GB.
## **Building the Container**
Lets get started on building the Minecraft server
1. **Create a directory for the Minecraft server files**:
```bash
# Make the folder
mkdir minecraft-server
# Enter the folder
cd minecraft-server
```
2. **Create an environment file for the Docker Container**:
- The _.env_ file allows us to specify variables used in the build process.
```bash
# Create a .env file
touch .env
# Open in a text editor
vim .env
# Enter the following variables
CONTAINER_NAME=minecraft-server
SERVER_MEM=4096 #change this to your desired value (in MB)
SERVER_JAR=<downloaded-server-file>.jar # Minecraft server jar file. Change this later
```
3. **Create the _docker-compose.yml_ file**:
```bash
# Create the file
touch docker-compose.yml`
# Open in a text editor
vim docker-compose.yml
```
- _docker-compose.yml_ is the spec of our Minecraft server.
- Build a docker image using context . and pass some ARGS.
- Attach volume .server-data, where Minecraft's files will be stored.
- Open network ports to access to the Docker container
- Give the docker container a name
- The container will always restart unless we tell it to stop.
```yaml
services:
minecraft-server:
build:
context: .
args:
SERVER_MEM: ${SERVER_MEM}
SERVER_JAR: ${SERVER_JAR}
volumes:
- .server-data:/server
ports:
- 25565:25565 # Game
- 25575:25575 # RCON
container_name: ${CONTAINER_NAME}
restart: unless-stopped
volumes:
server-data:
```
4. **Create the _Dockerfile_ file**:
- requested in docker-compose.yml build stage as context .
- The _Dockerfile_ is the spec for software running inside the container
```bash
# Create the file
touch Dockerfile
# Open the file in a text editor
vim Dockerfile
```
- We use the [eclipse-temurin:21](https://hub.docker.com/_/eclipse-temurin) image to provide the java JRE
- Use the required java version for the version of Minecraft you are running
- Collect the ARGs from the .env file
- Set the environment variables
- Set the working directory to /server which on our local system is .server-data
- Run the minecraft server jar with the ENV variables
```Dockerfile
FROM eclipse-temurin:21
ARG SERVER_MEM
ARG SERVER_JAR
ENV SERVER_MEM=${SERVER_MEM}
ENV SERVER_JAR=${SERVER_JAR}
WORKDIR /server
CMD echo "Minecraft Server is starting\n" && java -Xms128M -Xmx${SERVER_MEM}M -jar ${SERVER_JAR} nogui
```
## **Setup the Server files**
We’re almost there, just a few steps to go.
When you try to start the container, you might encounter the following error:
```bash
Minecraft Server is starting
Error: Unable to access jarfile server.jar
```
This happens because we haven't downloaded the server jar file yet. Let's do
that now
1. **Create a folder in the minecraft-server folder called .server-data**:
```bash
mkdir .server-data
cd .server-data
```
2. **Download a Minecraft server jar file**:
- [Vanilla Minecraft Server](https://www.minecraft.net/en-us/download/server)
- Right click the green link that says minecraft_server.<version>.jar and copy the link address
- Download with: `curl -o server.jar <link you copied here>`
- [Fabric Mod loader server](https://fabricmc.net/use/server/)
- Select the Minecraft version, Fabric Loader Version and the Installer Version of your choice. I tend to go with the latest.
- Download with: `Copy the curl command under CLI download`
3. **Go back to the root minecraft-server folder**
```bash
cd ..
```
4. **Edit SERVER_JAR in .env with the name of the .jar you just downloaded**:
```bash
# Open in a text editor
vim .env
# Enter the following variables
CONTAINER_NAME=minecraft-server
SERVER_MEM=4096
SERVER_JAR=<downloaded-server-file>.jar # Change this to the name of the .jar you downloaded
```
5. **Run the container to generate necessary files like 'eula.txt'**:
```bash
docker compose up
```
you will see something like this:
```bash
minecraft-server | Starting net.minecraft.server.Main
minecraft-server | [18:05:50] [ServerMain/INFO]: You need to agree to the EULA in order to run the server. Go to eula.txt for more info.
minecraft-server exited with code 0
```
6. **Accept the EULA**:
```bash
# edit eula.txt in a text editor
vim .server-data/eula.txt
# change `eula=false` to `eula=true`
eula=true
```
7. **Make any additional changes you want**:
- Notable files:
- **server.properties** - Configure server name, game mode, world type etc…
- **ops.json** - server operators (can be set in-game)
- **whitelist.json** - players allowed to join the server (can be set in-game)
## Run the Minecraft Server
1. **Run the container in detached mode**:
```bash
# The -d flag allows the container to run in detached mode, i.e., in the background
docker compose up -d
```
```bash
# monitor the logs as the server starts. Use CTRL+C to exit
docker logs minecraft-server --follow
# If you see the following lines, your server is up and running:
[18:17:01] [Server thread/INFO]: Time elapsed: 25529 ms
[18:17:01] [Server thread/INFO]: Done (34.571s)! For help, type "help"
```
## **Conclusion**
Congratulations! You've successfully set up a Minecraft server. Now it's time
to play!
There are many exciting possibilities from here, such as installing mods or
creating scripts to manage the server. Enjoy your Minecraft adventures!
+1 -3
View File
@@ -39,8 +39,6 @@ a **bare metal server that sucks a lot of power to a low power solution.**
- 4 x PoE hats
- 1 x 5 port PoE Switch
![Cluster(fix this image)](/img/pi-docker-swarm/cluster.webp)
### **Point Of This post**
After following this post you will have setup _Docker swarm_ on a cluster of Pis
@@ -329,7 +327,7 @@ vim hosts
```
- **_[piCluster]_** - specifies a group of hosts
- **_<ip address>_** - change these to the Pis IP addresses
- **_`<ip address>`_** - change these to the Pis IP addresses
**create the Pi Intercommunication keys**
+4 -4
View File
@@ -2,9 +2,9 @@
title: Securing SSH 🤖
description: Ever wanted to make your SSH connections more secure. Read this
tags:
- HomeLab
- RemoteAccess
- SSH
- homelab
- remoteaccess
- ssh
author: ahmza
date: 2021-12-07
draft: false
@@ -146,7 +146,7 @@ fine 😊
- Max Auth Tries 5
- PasswordAuthentication no
- PermitEmptyPasswords no
- AllowUsers <user>
- AllowUsers `<user>`
- ClientAliveInterval 180
``` bash
+1 -1
View File
@@ -3,7 +3,7 @@ title: Setup a HUGO Site
description: Always wanted to setup a static website. Look no further !! In this post we go over the basics of setting up a HUGO site
tags:
- blog
- HUGO
- hugo
- web
- development
author: ahmza
+5 -5
View File
@@ -36,7 +36,7 @@ wsl --install
Go to the Microsoft store and search for a Linux distribution. I prefer
to use the "Ubuntu" distribution.
![Microsoft Store](/img/WSL/ubuntu.webp)
![Ubuntu in the Microsoft Store](ubuntu.webp)
Once installed, go ahead and run the distribution, after it finishes setting
itself up it will ask you for a username and password. These credentials are
@@ -51,7 +51,7 @@ I use the windows terminal app to run the Ubuntu distribution, it makes
customising the environment a lot easier. To download it head over to the
Microsoft store and search for Windows Terminal and download it.
![Microsoft Store](/img/WSL/winterm.webp)
![Windows Terminal in the Microsoft Store](winterm.webp)
When you login to WSL it will not default to your home directory. To fix that go
to the Windows Terminal Settings look for Ubuntu or your distributions name and
@@ -61,11 +61,11 @@ change the Starting directory to
\\wsl$\<distro>\home\<username>
```
> Be sure to change "<distro>" to your distributions name
> Be sure to change `<distro>` to your distributions name
> Be sure to change "<username>" to your username
> Be sure to change `<username>` to your username
![winterm-settings](/img/WSL/winterm-settings.webp)
![Windows Terminal settings](winterm-settings.webp)
## **Conclusion**
+1
View File
@@ -1,5 +1,6 @@
---
title: Welcome
description: The mandatory hello world post — a quick intro to who I am and what this blog is about.
tags:
- blog
- misc
+8 -98
View File
@@ -1,44 +1,15 @@
# Caddy as a Reverse Proxy
This document describes how to run [Caddy](https://caddyserver.com/) as a
reverse proxy in front of the blog.
reverse proxy in front of the blog. It covers both deployment targets used by
this project: the Kubernetes (Raspberry Pi) cluster and the Docker Compose host
(Gimli).
It uses the custom [`caddy-cf`](https://github.com/ahmzaa/caddy-cf) image
(`ghcr.io/ahmzaa/caddy-cf:latest`) — a Caddy build with the **Cloudflare DNS
module** baked in.
## Deployment topologies
There are two supported ways to run Caddy in front of the blog. **Pick one.**
### 1. Cloudflare in front (current production) — HTTP only
```
Cloudflare (terminates TLS) -> Caddy (HTTP :80) -> SWS (blog:80)
```
Cloudflare proxies the domain and provides the public HTTPS certificate, so
Caddy only needs to serve plain **HTTP on :80** and reverse-proxy to the blog.
Caddy does **not** provision a TLS cert in this mode. This is the live setup and
its config is the committed [`Caddyfile`](../Caddyfile) at the repo root —
see [Cloudflare-fronted setup](#cloudflare-fronted-setup-http-only) below.
Set the Cloudflare **SSL/TLS mode to "Full"** so the Cloudflare→origin hop is
still encrypted at the network layer (e.g. over Netbird), even though Caddy's
listener is HTTP.
### 2. Caddy terminates TLS via Cloudflare DNS-01
```
Client -> Caddy (HTTPS :443, ACME DNS-01) -> SWS (blog:80)
```
Caddy obtains/renews the certificate itself using the ACME **DNS-01** challenge
through the Cloudflare API — no inbound `80`/`443` from the public internet is
required, which suits a Netbird-only setup with no Cloudflare proxy in front.
The stock Caddy image cannot do this; the `caddy-cf` build bundles the
Cloudflare DNS provider plugin. See the Docker Compose / Kubernetes examples
later in this document.
module** baked in. The stock Caddy image cannot solve the ACME **DNS-01**
challenge for Cloudflare; this custom build can, which is what lets us obtain
certificates without exposing ports `80`/`443` to the public internet.
## Why a reverse proxy?
@@ -50,7 +21,7 @@ the reverse proxy so that each layer owns exactly one job:
| Concern | Owned by | Notes |
| -------------------- | -------- | ------------------------------------------------- |
| TLS / HTTPS certs | Cloudflare *or* Caddy | Cloudflare in topology 1; Caddy (DNS-01) in topology 2 |
| TLS / HTTPS certs | Caddy | Automatic certs via Cloudflare **DNS-01** challenge |
| Compression (gzip/zstd) | Caddy | `encode` directive; SWS compression is off |
| Security headers | Caddy | Single source of truth, avoids duplicate headers |
| Serving static files | SWS | Reads from `/public`, sets `Cache-Control`/`ETag` |
@@ -79,72 +50,11 @@ Whatever the deployment, the SWS origin exposes:
- **Health endpoint:** `GET /health` → `200 OK`
- **Cache headers:** already set by SWS (Caddy should pass them through, not override)
Caddy only needs to handle TLS (or let Cloudflare do it), add compression +
Caddy only needs to terminate TLS (via Cloudflare DNS-01), add compression +
security headers, and forward requests to that origin.
---
## Cloudflare-fronted setup (HTTP only)
**This is the current production topology.** The canonical config is the
committed [`Caddyfile`](../Caddyfile) at the repo root; copy it to the
`caddy_cf` host and reload. Highlights:
- **`http://blog.ahmza.com`** — the explicit `http://` scheme binds Caddy to
`:80` only and stops it from trying to provision a TLS certificate (Cloudflare
already serves HTTPS to visitors).
- **`reverse_proxy blog:80`** — proxies to the blog (SWS) container by its
compose service name. Caddy and the blog container must share a Docker
network. Omitting this responder makes Caddy return an empty `NOP` response —
i.e. a **blank page**.
- **`encode zstd gzip`** — compression happens here (SWS has it disabled).
- **`header { ... }`** — security headers (SWS has them disabled).
- **`trusted_proxies cloudflare { ... }`** + **`client_ip_headers
Cf-Connecting-Ip X-Forwarded-For`** — so the real visitor IP is used for
logging/matchers, but only when the request genuinely comes from Cloudflare
(prevents header spoofing from any other source). The `cloudflare` IP source
([WeidiDeng/caddy-cloudflare-ip](https://github.com/WeidiDeng/caddy-cloudflare-ip),
baked into the `caddy-cf` image) auto-fetches the ranges from
<https://www.cloudflare.com/ips-v4/> and <https://www.cloudflare.com/ips-v6/>
and refreshes them on the configured `interval`, so there is no static list to
maintain:
```caddy
trusted_proxies cloudflare {
interval 12h
timeout 15s
}
```
`client_ip_headers` lists which header holds the real visitor IP:
`Cf-Connecting-Ip` is Cloudflare's single authoritative end-user IP, with
`X-Forwarded-For` as the fallback. It is only trusted for requests coming from
the `trusted_proxies` above.
> If you ever run without the `caddy-cloudflare-ip` plugin, you can instead
> pin the static ranges with `trusted_proxies static <ip/cidr ...>` copied
> from the Cloudflare IP pages, but then you must keep them in sync manually.
Deploy and reload:
```bash
# Put the Caddyfile in place on the caddy_cf host (e.g. into the ./conf mount),
# then reload without downtime:
docker exec caddy_cf caddy reload --config /etc/caddy/Caddyfile
# Verify from the host (expect HTTP 200, Content-Encoding: gzip, X-Frame-Options):
curl -sI -H "Accept-Encoding: gzip" http://localhost/ | grep -iE 'HTTP|content-encoding|x-frame'
```
> **Cloudflare SSL/TLS mode:** set it to **Full** so the Cloudflare→origin hop
> is encrypted at the network layer (e.g. over Netbird), even though Caddy's
> listener is plain HTTP.
---
The remaining sections describe **topology 2** (Caddy terminates TLS itself via
the Cloudflare DNS-01 challenge) for setups without a Cloudflare proxy in front.
## Docker Compose (Gimli)
Run Caddy and the blog container on the same Docker network. Caddy reaches the
+1 -1
View File
@@ -1 +1 @@
<a href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}{{ if strings.HasPrefix .Destination "http" }} target="_blank"{{ end }}>{{ .Text | safeHTML }}</a>
<a href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}{{ if strings.HasPrefix .Destination "http" }} target="_blank" rel="noopener noreferrer"{{ end }}>{{ .Text | safeHTML }}</a>
+3 -3
View File
@@ -1,6 +1,6 @@
<br>
<div class="flex items-center gap-x-5">
<a class="text-sm text-neutral-500 dark:text-neutral-400 rel='me'" href="https://mastodon.social/@ahmza">Mastodon</a>
<a class="text-sm text-neutral-500 dark:text-neutral-400 rel='me'" href="https://github.com/ahmzaa">Github</a>
<a class="text-sm text-neutral-500 dark:text-neutral-400 rel='me'" href="https://www.linkedin.com/in/ahmza/">Linkedin</a>
<a class="text-sm text-neutral-500 dark:text-neutral-400" rel="me noopener noreferrer" target="_blank" href="https://mastodon.social/@ahmza">Mastodon</a>
<a class="text-sm text-neutral-500 dark:text-neutral-400" rel="me noopener noreferrer" target="_blank" href="https://github.com/ahmzaa">Github</a>
<a class="text-sm text-neutral-500 dark:text-neutral-400" rel="me noopener noreferrer" target="_blank" href="https://www.linkedin.com/in/ahmza/">Linkedin</a>
</div>
+1 -1
View File
@@ -1 +1 @@
<img src="{{ .Get "url"}}" alt="{{ .Get "alt"}}" style="display:block;margin-left:auto;margin-right:auto;width:50%;height:auto;padding:10px;">
<img src="{{ .Get "url"}}" alt="{{ .Get "alt"}}" loading="lazy" decoding="async" style="display:block;margin-left:auto;margin-right:auto;width:50%;height:auto;padding:10px;">
+1 -1
View File
@@ -1,4 +1,4 @@
<video autoplay loop muted playsinline aria-label='{{ .Get "label"}}' style="display:block;margin-left:auto;margin-right:auto;width:50%;height:auto;padding:10px;">
<video autoplay loop muted playsinline preload="metadata" aria-label='{{ .Get "label"}}' style="display:block;margin-left:auto;margin-right:auto;width:50%;height:auto;padding:10px;">
{{ with .Get "mp4" }}<source src="{{ . }}" type="video/mp4">{{ end }}
{{ with .Get "webm" }}<source src="{{ . }}" type="video/webm">{{ end }}
</video>
+1 -1
View File
@@ -23,7 +23,7 @@ media_folder: "assets/uploaded/img"
public_folder: "/uploaded/img"
## SiteTitle
site_url: htpps://blog.ahmza.com
site_url: https://blog.ahmza.com
display_url: blog.ahmza.com
logo_url: https://blog.ahmza.com/logo.webp
+8 -2
View File
@@ -8,7 +8,13 @@
<!-- Include the script that enables Netlify Identity on this page. -->
</head>
<body>
<!-- Include the script that builds the page and powers Decap CMS -->
<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>
<!-- Sveltia CMS, pinned to a specific version with Subresource Integrity.
Bump the version + regenerate the integrity hash when upgrading:
curl -sS https://cdn.jsdelivr.net/npm/@sveltia/cms@<ver>/dist/sveltia-cms.js \
| openssl dgst -sha384 -binary | openssl base64 -A -->
<script
src="https://cdn.jsdelivr.net/npm/@sveltia/cms@0.172.4/dist/sveltia-cms.js"
integrity="sha384-Sj4Mfbg9OjjwG2ZE/YeUYu7xbZRTXGFg/wa/nszj3KzItKuRLEmGqSpV5C9YI2Ge"
crossorigin="anonymous"></script>
</body>
</html>
+4 -3
View File
@@ -31,9 +31,10 @@ cache-control-headers = true
#### Routing
# SPA-style fallback: serve index.html when a path is not found on disk,
# mirroring the previous nginx `try_files $uri $uri/ /index.html`.
page-fallback = "/public/index.html"
# No SPA-style page fallback: this is a static Hugo site, not a single-page app.
# Missing paths should return Hugo's generated 404.html with a real 404 status
# (SWS serves /public/404.html automatically) rather than masking broken links
# with a 200 homepage response, which harms SEO (soft 404s).
#### Security