diff --git a/content/post/static-sites-with-mash.md b/content/post/static-sites-with-mash.md new file mode 100644 index 0000000..1ea879a --- /dev/null +++ b/content/post/static-sites-with-mash.md @@ -0,0 +1,171 @@ +--- +title: "Hosting static sites with Traefik" +date: 2023-07-16T15:10:10+02:00 +draft: false +image: "/uploads/static-sites-with-traefik/html.png" +categrories: ['English'] +tags: ['MASH', 'hugo', 'english', 'ansible', 'traefik', 'SWS'] +--- + +# Hosting Static Sites with [Traefik](https://traefik.io/) and [Static Web Server](https://static-web-server.net/features/docker/#run-a-container) + +Traefik is amazing to host complex services like with containers. On the other hand it's harder than you'd think to host a simple static html site. I wanted to share my current approach that is based on [Static Web Server Project](https://static-web-server.net/features/docker/#run-a-container). + + +## Static Web Server (SWS) + +Static Web Server (or SWS abbreviated) is a simple and really fast web server with the goal to serve static web files or assets. The tiny docker image is only 4 MB with a small memory footprint. We can therefore afford to run a container for each static site. + +## Architecture + + +On the server we set up all static sites in one folder called `static-sites`. As we run the SWS with [docker-compose](https://docs.docker.com/compose/) we add the `docker-compose.yml` to this folder too. The following is an example setup with two static sites on seperate domains. + + +``` +| static-sites +| +| docker-compose.yml +| - domain1.example.org + | - index.html +| - domain2.example.org + | - index.html + | - fonts + | - Open-Dyslexic.odf +``` + +For each domain we add a folder. I like to name them by the domain name but this is not necessary (just remember the volume in the `docker-compose.yml` too). + +With this done we can now fill the appropriate information in the `docker-compose.yml`. Copy the following and replace `domain1.example.org`, `domain2.example.org`, `site-one` and `site-two`. + + +```yaml +version: "3.3" + +services: + domain1.example.org: + image: joseluisq/static-web-server:2 + container_name: "domain1.example.org" + environment: + # Note: those envs are customizable but also optional + - SERVER_PORT=8080 + - SERVER_ROOT=/public + - SERVER_LOG_LEVEL=info + volumes: + - ./domain1.example.org:/public + labels: + - "traefik.enable=true" + - "traefik.docker.network=traefik" + - "traefik.http.routers.site-one.rule=Host(`domain1.example.org`)" + - "traefik.http.routers.site-one.service=site-one" + - "traefik.http.routers.site-one.entrypoints=web-secure" + - "traefik.http.routers.site-one.tls=true" + - "traefik.http.routers.site-one.tls.certResolver=default" + - "traefik.http.services.site-one.loadbalancer.server.port=8080" + networks: + - traefik + + domain2.example.org: + image: joseluisq/static-web-server:2 + container_name: "domain2.example.org" + environment: + # Note: those envs are customizable but also optional + - SERVER_PORT=8080 + - SERVER_ROOT=/public + - SERVER_LOG_LEVEL=info + volumes: + - ./domain2.example.org:/public + labels: + - "traefik.enable=true" + - "traefik.docker.network=traefik" + - "traefik.http.routers.site-two.rule=Host(`domain2.example.org`)" + - "traefik.http.routers.site-two.service=site-two" + - "traefik.http.routers.site-two.entrypoints=web-secure" + - "traefik.http.routers.site-two.tls=true" + - "traefik.http.routers.site-two.tls.certResolver=default" + - "traefik.http.services.site-two.loadbalancer.server.port=8080" + networks: + - traefik + +networks: + traefik: + name: traefik + external: true +``` + +This assumes traefik runs in a docker-network called traefik. This network must already exist. + + +As a last step add at least a `index.html` in the appropriate folder. Then you can start the webserver with `docker-compose up`. Add `-d` to run it in the background. + + +# Deploying static sites + +Deploying files manually (via Filezilla, scp or rsync) is not something I like to do. I therefore normally set up a CI job to automatically deploy the site when I push a new commit to GitHub, either via GitHub Actions or my [Woodpecker CI](https://woodpecker-ci.org/docs/usage/intro) instance. + +I order to do that I + +* create a new user on the server, specifically for that purpose (one per site). The command is `useradd USERNAME -m` +* create a SSH key without a password `ssh-keygen -t ed25519 -a 100 -C "COMMENT" -f FILENAME` +* copy the public key that was just created at `FILENAME.pub` on the server in the textfile `/home/USERNAME/.ssh/authorized_keys` +* Add the private key to the secrets of your CI + +A typical CI configuration will look like this with a static site and GitHub Actions + +```yaml +name: Deploy Production Website via SSH + +on: + push: + branches: [main] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Deploy to Server + uses: easingthemes/ssh-deploy@main + env: + SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} + ARGS: "-rltgoDzvO --delete" + SOURCE: "" + REMOTE_HOST: ${{ secrets.REMOTE_HOST }} + REMOTE_USER: ${{ secrets.REMOTE_USER }} + TARGET: ${{ secrets.REMOTE_PRODUCTION_TARGET }} + EXCLUDE: ".github/, .gitignore" +``` + +or this, when using [HUGO](https://gohugo.io/) and Woodpecker CI + +```yaml +--- + +pipeline: + build: + image: klakegg/hugo + commands: + - hugo + + deploy: + image: appleboy/drone-scp + settings: + strip_components: 1 + host: + - example.org + username: moanos + target: /home/USERNAME/static-sites/ + source: public/ + key: + from_secret: ssh_key + +``` + + + + + + +not manually put the files on the server diff --git a/static/uploads/static-sites-with-traefik/html.png b/static/uploads/static-sites-with-traefik/html.png new file mode 100644 index 0000000..d7252ba Binary files /dev/null and b/static/uploads/static-sites-with-traefik/html.png differ