diff options
author | Julien Dessaux | 2025-03-09 20:31:45 +0100 |
---|---|---|
committer | Julien Dessaux | 2025-03-09 20:31:45 +0100 |
commit | ab877f967da02b7cc4d140c962e99f3b059997de (patch) | |
tree | 79a6de4f810870d2cc6aed4bc21d2849ea4202b6 | |
parent | feat(blog): add luks unlock via ssh article (diff) | |
download | www-master.tar.gz www-master.tar.bz2 www-master.zip |
-rw-r--r-- | GNUmakefile | 81 | ||||
-rw-r--r-- | README.md | 67 | ||||
-rwxr-xr-x | deploy/build-image.sh | 64 | ||||
-rw-r--r-- | deploy/headers_secure.conf | 10 | ||||
-rw-r--r-- | deploy/headers_static.conf | 3 | ||||
-rw-r--r-- | deploy/nginx.conf | 60 | ||||
-rw-r--r-- | deploy/www.yaml | 134 |
7 files changed, 87 insertions, 332 deletions
diff --git a/GNUmakefile b/GNUmakefile index 28762ef..d2c51d9 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,55 +1,66 @@ -SHELL := bash -.SHELLFLAGS := -eu -o pipefail -c -.ONESHELL: +.DEFAULT_GOAL := help .DELETE_ON_ERROR: -MAKEFLAGS += --warn-undefined-variables MAKEFLAGS += --no-builtin-rules +MAKEFLAGS += --warn-undefined-variables +.ONESHELL: +SHELL := bash +.SHELLFLAGS := -eu -o pipefail -c -CACHEDIR=/tmp/hugo-cache-$(USER) -DESTDIR=public/ -HOSTNAME=$(shell hostname -f) -REVISION=$(shell git rev-parse HEAD) +##### Variables ################################################################ +CACHEDIR := /tmp/hugo-cache-$(USER) +DESTDIR := public/ +HOSTNAME := $(shell hostname -f) +REVISION := $(shell git rev-parse HEAD) +##### Development ############################################################## .PHONY: build -build: ## make build # builds an optimized version of the website in $(DESTDIR) +build: ## make build + # TODO make sure to stash everything in content/ ? @echo "----- Generating site -----" - hugo --gc --minify --cleanDestinationDir -d $(DESTDIR) --cacheDir $(CACHEDIR) --buildFuture + hugo --gc --minify --cleanDestinationDir -d $(DESTDIR) \ + --cacheDir $(CACHEDIR) --buildFuture cp public/index.json search/ cp public/search/index.html search/ - (cd search && CGO_ENABLED=0 go build -ldflags '-s -w -extldflags "-static"' ./search.go) - -.PHONY: buildah -buildah: ## make buildah # builds the container images - deploy/build-image.sh + cd search + CGO_ENABLED=0 go build -ldflags '-s -w -extldflags "-static"' ./search.go .PHONY: clean -clean: ## make clean # removed all $(DESTDIR) contents +clean: ## make clean @echo "----- Cleaning old build -----" rm -f search/index.html search/index.json search/search rm -rf $(DESTDIR) +.PHONY: serve +serve: ## make serve # hugo web server development mode + hugo serve --disableFastRender --noHTTPCache \ + --cacheDir $(CACHEDIR) --bind 0.0.0.0 --port 1313 \ + -b http://$(HOSTNAME):1313/ --buildFuture --navigateToChanged + +##### Operations ############################################################### .PHONY: deploy -deploy: ## make deploy # deploy the website to myth.adyxax.org - rsync -a $(DESTDIR) root@myth.adyxax.org:/srv/www/ - rsync search/search root@myth.adyxax.org:/srv/www/search/search - ssh root@myth.adyxax.org "systemctl restart www-search" +deploy: ## make deploy + rsync -a $(DESTDIR) root@www.adyxax.org:/srv/www/ + rsync search/search root@www.adyxax.org:/usr/local/bin/www-search + ssh root@www.adyxax.org "systemctl restart www-search" -.PHONY: deploy-kube -deploy-kube: ## make deploy-kube # deploy the website to the active kubernetes context - sed -i deploy/www.yaml -e 's/^\(\s*image:[^:]*:\).*$$/\1$(REVISION)/' - kubectl apply -f deploy/www.yaml +##### Quality ################################################################## +.PHONY: check +check: ## run all code checks + (cd search && go mod verify && go vet ./...) -.PHONY: help -help: - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' +.PHONY: tidy +tidy: ## tidy up the code + (cd search && go fmt ./... && go mod tidy -v) -.PHONY: push -push: ## make push # push the built images to quay.io - buildah push adyxax/www quay.io/adyxax/www:$(REVISION) - buildah push adyxax/www-search quay.io/adyxax/www-search:$(REVISION) +##### Utils #################################################################### +.PHONY: confirm +confirm: + @echo -n 'Are you sure? [y/N] ' && read ans && [ $${ans:-N} = y ] -.PHONY: serve -serve: ## make serve # hugo web server development mode - hugo serve --disableFastRender --noHTTPCache --cacheDir $(CACHEDIR) --bind 0.0.0.0 --port 1313 -b http://$(HOSTNAME):1313/ --buildFuture --navigateToChanged +.PHONY: help +help: + @grep -E '^[a-zA-Z\/_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' | sort -.DEFAULT_GOAL := help +.PHONY: no-dirty +no-dirty: + git diff --exit-code @@ -1,10 +1,18 @@ # www : My personal website -My name is Julien Dessaux, also known by my pseudonym Adyxax : welcome to my personal website! +My name is Julien Dessaux, also known by my pseudonym Adyxax: welcome to my +personal website! -These pages are an aggregation of various thoughts and tutorials I accumulated over my years of service as a system and network administrator and architect. Topics covered are open source, BSD and GNU/Linux system administration, and networking. It is a personal space that I try to fill up with my experience and knowledge of computer systems and network administration in the hope it serves others. You can learn more about me on this page. +These pages are an aggregation of various thoughts and tutorials I accumulated +over my years of service as a system and network administrator and architect. +Topics covered are open source, BSD and GNU/Linux system administration, and +networking. It is a personal space that I try to fill up with my experience and +knowledge of computer systems and network administration in the hope it serves +others. You can learn more about me on this page. -I hope you feel welcome here, do not hesitate to leave a message at julien -DOT- dessaux -AT- adyxax -DOT- org. You can ask for a translation, some more details on a topic covered here, or just say hi or whatever ;-) +I hope you feel welcome here, do not hesitate to leave a message at julien -DOT- +dessaux -AT- adyxax -DOT- org. You can ask for a translation, some more details +on a topic covered here, or just say hi or whatever ;-) Have a good time! @@ -18,37 +26,44 @@ Have a good time! ## Dependencies -go is required for the search feature. Only go version >= 1.22 on linux amd64 (Gentoo) is being regularly tested. +go is required for the search feature. Only go version >= 1.22 on linux amd64 +(Gentoo) is being regularly tested. -hugo is required in order to build the website html pages. Only hugo >= 0.111.3 is being regularly tested. - -buildah is optionally required in order to build the container images with my deploy script. +hugo is required in order to build the website html pages. Only hugo >= 0.111.3 +is being regularly tested. ## Quick Start -There is a makefile with everything you need, just type `make help` (or `gmake help` if running BSD). +There is a makefile with everything you need, just type `make help` (or `gmake +help` if running BSD). ## Hugo -Contrary to popular usage, I do not use a theme with hugo. I decided to simplify write my own in order to keep it light and simple. Here is a breakdown of each folder's contents: - -- assets/: css files, which will be compiled into a single minified file. -- content/: markdown files - - blog/: blog section of this website. - - books/: a log of simple reviews of books I read. - - docs/: wiki like section, where information is not sorted just chronologically like in the blog section. - - search/: dummy section I need for the search feature. -- deploy/: container images building script. -- layouts/: html, json and rss templates. Also some useful hugo shortcodes. -- search: the go program that powers the search feature. -- static: favicon, blog images and schematics. +Contrary to popular usage, I do not use a theme with hugo. I decided to write my +own in order to keep it light and simple. Here is a breakdown of each folder's +contents: + +- `assets/`: css files, which will be compiled into a single minified file. +- `content/`: markdown files + - `blog/`: blog section of this website. + - `books/`: a log of simple reviews of books I read. + - `docs/`: wiki like section, where information is not sorted just + chronologically like in the blog section. + - `search/`: dummy section I need for the search feature. +- `deploy/`: container images building script. +- `layouts/`: html, json and rss templates. Also some useful hugo shortcodes. +- `search/`: the go program that powers the search feature. +- `static/`: favicon, blog images and schematics. ## Search -Hugo can easily generate a json index of the website, and according to my google-fu hugo users use javascript solutions to implement search on top of this. I was not satisfied by the idea of having javascript download the whole website index and running searches locally, but I found no alternative. Since I love having a javascript free website I wanted to keep it that way if possible, so I designed an alternative. - -The search folders contains code for a go webservice that can handle search queries and serve results. It is fully integrated in the container images build process to maintain a coherent look with the website. For more details, see the related [blog article](https://www.adyxax.org/blog/2021/09/19/implementing-a-search-feature-for-my-hugo-static-website/). - -## Kubernetes +Hugo can easily generate a json index of the website, and according to my +google-fu hugo users use javascript solutions to implement search on top of +this. I was not satisfied by the idea of having javascript download the whole +website index and running searches locally, but I found no alternative. I +therefore designed an alternative. -I host this website on a k3s cluster. An example manifest can be found in the deploy folder. +The search folder contains code for a go webservice that can handle search +queries and serve results. It is fully integrated to maintain a coherent look +with the website. For more details, see the related [blog +article](https://www.adyxax.org/blog/2021/09/19/implementing-a-search-feature-for-my-hugo-static-website/). diff --git a/deploy/build-image.sh b/deploy/build-image.sh deleted file mode 100755 index a9cf511..0000000 --- a/deploy/build-image.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ret=0; buildah images adyxax/alpine &>/dev/null || ret=$? -if [[ "${ret}" != 0 ]]; then - buildah rmi --all - ALPINE_LATEST=$(curl --silent https://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/x86_64/ | - perl -lane '$latest = $1 if $_ =~ /^<a href="(alpine-minirootfs-\d+\.\d+\.\d+-x86_64\.tar\.gz)">/; END {print $latest}' - ) - if [ ! -e "./${ALPINE_LATEST}" ]; then - echo "Fetching ${ALPINE_LATEST}..." - curl --silent "https://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/x86_64/${ALPINE_LATEST}" \ - --output "./${ALPINE_LATEST}" - fi - - ctr=$(buildah from scratch) - buildah add "${ctr}" "${ALPINE_LATEST}" / - buildah run "${ctr}" /bin/sh -c 'apk upgrade --no-cache' - buildah run "${ctr}" /bin/sh -c 'apk add --no-cache pcre sqlite-libs' - buildah commit "${ctr}" adyxax/alpine - buildah rm "${ctr}" -fi - -ret=0; buildah images adyxax/hugo &>/dev/null || ret=$? -if [[ "${ret}" != 0 ]]; then - hugo=$(buildah from adyxax/alpine) - buildah run "${hugo}" /bin/sh -c 'apk add --no-cache go git hugo make' - buildah commit "${hugo}" adyxax/hugo -else - hugo=$(buildah from adyxax/hugo) -fi - -buildah run -v "${PWD}":/www "${hugo}" -- sh -c 'cd /www; make build' -buildah rm "${hugo}" - -ret=0; buildah images adyxax/nginx &>/dev/null || ret=$? -if [[ "${ret}" != 0 ]]; then - nginx=$(buildah from adyxax/alpine) - buildah run "${nginx}" /bin/sh -c 'apk add --no-cache nginx' - buildah commit "${nginx}" adyxax/nginx -else - nginx=$(buildah from adyxax/nginx) -fi - -(cd deploy && buildah copy "${nginx}" nginx.conf headers_secure.conf headers_static.conf /etc/nginx/) -buildah config \ - --author 'Julien Dessaux' \ - --cmd nginx \ - --port 80 \ - "${nginx}" -buildah copy "${nginx}" public /var/www/www.adyxax.org - -buildah commit "${nginx}" adyxax/www -buildah rm "${nginx}" - -ctr=$(buildah from scratch) -buildah copy "${ctr}" search/search / -buildah config \ - --author 'Julien Dessaux' \ - --cmd /search \ - --port 8080 \ - "${ctr}" -buildah commit "${ctr}" adyxax/www-search -buildah rm "${ctr}" diff --git a/deploy/headers_secure.conf b/deploy/headers_secure.conf deleted file mode 100644 index 6dfc381..0000000 --- a/deploy/headers_secure.conf +++ /dev/null @@ -1,10 +0,0 @@ -# A+ on https://securityheaders.io/ -add_header X-Frame-Options deny; -add_header X-XSS-Protection "1; mode=block"; -add_header X-Content-Type-Options nosniff; -add_header Referrer-Policy strict-origin; -add_header Cache-Control no-transform; -add_header Content-Security-Policy "script-src 'unsafe-inline'"; -add_header Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()"; -# 6 months HSTS pinning -add_header Strict-Transport-Security max-age=16000000; diff --git a/deploy/headers_static.conf b/deploy/headers_static.conf deleted file mode 100644 index 2b3f31d..0000000 --- a/deploy/headers_static.conf +++ /dev/null @@ -1,3 +0,0 @@ -include headers_secure.conf; -# Infinite caching -add_header Cache-Control "public, max-age=31536000, immutable"; diff --git a/deploy/nginx.conf b/deploy/nginx.conf deleted file mode 100644 index d4fe348..0000000 --- a/deploy/nginx.conf +++ /dev/null @@ -1,60 +0,0 @@ -user nginx; -worker_processes 1; -daemon off; - -events { - # The maximum number of simultaneous connections that can be opened by - # a worker process - worker_connections 1024; -} - -http { - # Includes mapping of file name extensions to MIME types of responses - # and defines the default type. - include /etc/nginx/mime.types; - default_type application/octet-stream; - - # Don't tell nginx version to the clients. Default is 'on'. - server_tokens off; - - # Specifies the maximum accepted body size of a client request, as - # indicated by the request header Content-Length. If the stated content - # length is greater than this size, then the client receives the HTTP - # error code 413. Set to 0 to disable. Default is '1m'. - client_max_body_size 1m; - - # Sendfile copies data between one FD and other from within the kernel, - # which is more efficient than read() + write(). Default is off. - sendfile on; - - # Causes nginx to attempt to send its HTTP response head in one packet, - # instead of using partial frames. Default is 'off'. - tcp_nopush on; - - # Enables or disables the use of the TCP_NODELAY option. The option is - # enabled when a connection is transitioned into the keep-alive state. - # Additionally, it is enabled on SSL connections, for unbuffered - # proxying, and for WebSocket proxying. - tcp_nodelay on; - - # Specifies the main log format. - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - server { - listen 80; - listen [::]:80; - server_name _; - root /var/www/www.adyxax.org/; - index index.html; - error_page 404 /404.html; - - location /static { - include /etc/nginx/headers_static.conf; - } - location / { - include headers_secure.conf; - add_header Cache-Control "private, max-age=0, must-revalidate, no-transform"; - } - } -} diff --git a/deploy/www.yaml b/deploy/www.yaml deleted file mode 100644 index 6613173..0000000 --- a/deploy/www.yaml +++ /dev/null @@ -1,134 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: www ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: www - name: www - labels: - app: www -spec: - replicas: 1 - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - type: RollingUpdate - selector: - matchLabels: - app: www - template: - metadata: - labels: - app: www - spec: - containers: - - name: www - image: quay.io/adyxax/www:2021111202 - ports: - - containerPort: 80 - readinessProbe: - httpGet: - path: '/' - port: 80 - initialDelaySeconds: 1 - timeoutSeconds: 1 - livenessProbe: - httpGet: - path: '/' - port: 80 - initialDelaySeconds: 1 - timeoutSeconds: 1 - lifecycle: - preStop: - exec: - command: ["/bin/sh", "-c", "sleep 10"] - - name: search - image: quay.io/adyxax/www-search:2021111202 - ports: - - containerPort: 8080 - readinessProbe: - httpGet: - path: '/search/' - port: 8080 - initialDelaySeconds: 1 - timeoutSeconds: 1 - livenessProbe: - httpGet: - path: '/search/' - port: 8080 - initialDelaySeconds: 1 - timeoutSeconds: 1 - lifecycle: - preStop: - exec: - command: ["/bin/sh", "-c", "sleep 10"] ---- -apiVersion: v1 -kind: Service -metadata: - namespace: www - name: www -spec: - type: ClusterIP - selector: - app: www - ports: - - protocol: TCP - port: 80 - targetPort: 80 - name: www - - protocol: TCP - port: 8080 - targetPort: 8080 - name: search ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - nginx.ingress.kubernetes.io/configuration-snippet: | - more_set_headers "Content-Security-Policy: script-src 'unsafe-inline'"; - namespace: www - name: www -spec: - ingressClassName: nginx - tls: - - secretName: wildcard-adyxax-org - rules: - - host: www.adyxax.org - http: - paths: - - path: '/' - pathType: Prefix - backend: - service: - name: www - port: - number: 80 - - path: '/search' - pathType: Prefix - backend: - service: - name: www - port: - number: 8080 ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - namespace: www - name: redirects - annotations: - nginx.ingress.kubernetes.io/permanent-redirect: https://www.adyxax.org/ - nginx.ingress.kubernetes.io/permanent-redirect-code: "308" -spec: - ingressClassName: nginx - tls: - - secretName: wildcard-adyxax-org - rules: - - host: adyxax.org - - host: wiki.adyxax.org |