5.5 KiB
title | date | draft | image | categrories | tags | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Hosting static sites with Traefik | 2023-07-16T15:10:10+02:00 | false | /uploads/static-sites-with-traefik/html.png |
|
|
Hosting Static Sites with Traefik and Static Web Server
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.
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 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
.
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 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
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 and Woodpecker CI
---
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