Initial commit
This commit is contained in:
commit
961e7aebe4
14 changed files with 289 additions and 0 deletions
1
.dockerignore
Normal file
1
.dockerignore
Normal file
|
@ -0,0 +1 @@
|
|||
run/
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
run/
|
30
Containerfile
Normal file
30
Containerfile
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Remember to update!
|
||||
FROM docker.io/nginx:1.29.0-alpine-slim
|
||||
|
||||
ENV DOMAIN="example.localhost"
|
||||
ENV SERVER_ID="server"
|
||||
ENV RELOAD_FILE="/var/run/nginx-reload"
|
||||
ENV ACME_CHALLENGE_URL="http://acme-challenge.${DOMAIN}/.well-known/acme-challenge/"
|
||||
|
||||
RUN apk add --no-cache \
|
||||
inotify-tools # For reloading
|
||||
|
||||
# Copy the configuration files
|
||||
COPY nginx /etc/nginx/
|
||||
|
||||
# Copy the dummy certificate files
|
||||
COPY certificates /etc/ssl/
|
||||
|
||||
# Copy the entrypoint scripts
|
||||
COPY --chmod=0755 docker-entrypoint.d /docker-entrypoint.d/
|
||||
|
||||
# Copy the scripts
|
||||
COPY --chmod=0755 scripts/ /opt/scripts/
|
||||
RUN ln -s /opt/scripts/reload.sh /usr/local/bin/reload
|
||||
|
||||
# Create the volumes for certificates and website files
|
||||
VOLUME /etc/ssl/certs
|
||||
VOLUME /var/www/html
|
||||
|
||||
# Expose the ports for HTTP and HTTPS
|
||||
EXPOSE 80/tcp 443/tcp 443/udp
|
26
README.md
Normal file
26
README.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
This is a container that helps host a static website.
|
||||
|
||||
## Configuration
|
||||
|
||||
**Requires** the following mounts:
|
||||
- `/etc/ssl/certs/$DOMAIN`: For certificates (`fullchain.pem` and `privkey.pem`)
|
||||
- `/var/www/html/$DOMAIN`: Website files, `index.html` goes right here
|
||||
|
||||
**Requires** the following environment variables:
|
||||
- `DOMAIN`: The domain
|
||||
- `ACME_CHALLENGE_HOST`: The source of `.well-known/acme-challenge`
|
||||
|
||||
You're also encouraged to provide your own:
|
||||
- `/etc/ssl/dhparam.pem`, generated with:
|
||||
```bash
|
||||
openssl dhparam -out dhparam.pem 4096
|
||||
```
|
||||
- `/etc/ssl/snakeoil.key` & `/etc/ssl/snakeoil.pem`, generated with:
|
||||
```bash
|
||||
openssl req -new -x509 -days 398 -noenc -out snakeoil.pem -keyout snakeoil.key -subj "/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd"
|
||||
```
|
||||
- `SERVER_ID`: How to call this server (for info)
|
||||
- **Mount** `/var/run/nginx-reload`: modify this file to reload nginx
|
||||
|
||||
## TODO
|
||||
- support for multiple domains
|
13
certificates/dhparam.pem
Normal file
13
certificates/dhparam.pem
Normal file
|
@ -0,0 +1,13 @@
|
|||
-----BEGIN DH PARAMETERS-----
|
||||
MIICDAKCAgEAgzMa8BTPT60M95CnRmSc69n9b+hY+9T8jte8HNEQfu07sJQkKJfK
|
||||
c5znc+bR1fnt0CFexz2rm4TUig082R8zEopfoXztR2XEtIEqiJ9Lt2HGx9t2GFi+
|
||||
aYAvB7Y8qvFq67dJdIzqVEkjoRBZwUiOAbRuaL54LOz5pBBv0217ezzbfEYtItAu
|
||||
DdOQOZEfQ1+N7PJ9QQpfDJVl7rKfzna0gF3Wox1q5QtNqks44TWYiZqs0eOWkged
|
||||
18PEsrwYpeiEqz7/ytaLONB1YU2FSrnYQFE9e7iMRMddEPRoor3VKeRC7gWTNIsB
|
||||
Kkt2LfDX0lXO7bEuKMEoGvt7xkJ2XlUDjtc3htF5BKcuCWpygXTBVtZ+tkdPpjYP
|
||||
fp/gS2X060GPI3Egxtua2kHj3zHiebQHn000CxLgSbUUwNxzhThoMONF7v4Z3R9D
|
||||
TUYLsu1No6FzQbotJiFepoSkI9WqhdMO/9VYu/EwBGq+Wlhqo9mh9KQL4uMdIC4P
|
||||
v1ZoazRRn6ioaPLwabwvsZnzu+TxQBuAolDB2rN7dSljXNinG/y2Jv6y5LJZlFI9
|
||||
nSVm22Sm+mwHz+rlfBmipaIxMTxN4UyxSx9oLEMj0c0PDXmbPaxJ78tw2+RG9dLn
|
||||
cbXROxsE/0MehRpDM6ksn/O2XRXFeSs0ol6Z4EZ98zxUa4crDanUD0cCAQICAgFF
|
||||
-----END DH PARAMETERS-----
|
28
certificates/snakeoil.key
Normal file
28
certificates/snakeoil.key
Normal file
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDc2YmG90vmG/Og
|
||||
1hpufu81YjDaPNGOdsDcjagA0mFFs2kGATrg95JZNcu5Aef8ropEIV9mu3++zP8K
|
||||
VjPD+7HJ2eCkT1tT4IAy9q4JQAEv1efyjHbcfgXAhPRhil2hSICS2lCnL0dTPVFk
|
||||
/Pjj5tl+vatzoiLDmnSpbETjID+dG7IBYxOtVlH61ZEMV2jUHnGPcZfv5UFMQD6m
|
||||
hqV1VSzTO+X4EhT1fVIRzvM3A21YbKof3z9HxxldizhjV7kAihBrD/2i1EDOAZwF
|
||||
tufQVG8Dy5+pUl21xcBfcmAJ8Bqz5Dk6jwClRUMSGv+WNb+RG7an1UkszVnPGv0G
|
||||
D65UnVDtAgMBAAECggEABIUSNrgobj7rs0K2e0TvRdcq20iL3F/LTig7BDtKANht
|
||||
YZFUYGbIsLk0YGas1gPHciIBtxNGx8Ofw5kkiZIE3zXtjkdOfe62CPT59lgAPjeh
|
||||
PdpIk3YjzX8bFkTz6hlXAkpkBKvnyIkUeZ3gxR9EG78re1wZ3Il0ckQ0O7a8/ozZ
|
||||
D4OSnm57Ya9vSDboph+kfa9zH30dPKbkjyaJOsFGgn0/wgQ/9omir3Ty0nqMPD3r
|
||||
vgertcek5GXXXd0HxZ2nDPX5K3v3eKNfq5ivdDzEi2rH4JHrEjIUaUehqNhl+ah8
|
||||
v5u9lfaRsN0AvV7Cx3ZoV2sh9s/F0vO9N42bhAQteQKBgQD4ldOFXHi1yQAnyNbT
|
||||
MsvU3UAdffbzKg7u3NxtBInFLpXbgkTDkCzQK1flyJeYMBSQQxniPhNKVVMjJaOa
|
||||
FBlPFssf0uV3VHHj9bJsegnHC1VUaE6mUMIlZ9L1En1An21q+fdGdf58OK0ozWzP
|
||||
SeK42pAGZul/hXGKkTl1NXk8OQKBgQDjb+zdSUJsZfmunYHZ6BQhDBpTFy0a4f0q
|
||||
LcGf4e4LWzYArN2X3buKhPRNn8j7g6ThU9c2HErAYAVbfRdMRjW+372EWf+v7Skq
|
||||
KKq3kf2WbFn9UDo6yNs3dQOWM8yX7w+1LsvkbDqUYMOpYdwj0Ts5Sj7Xa82vrnmm
|
||||
gdloMcLiVQKBgGcE8JwcLopnuoDCYwUzz/Vvm9qdEXLEw1uKfG9Rqibln4VQ/15s
|
||||
qaW70LmR4AFaK6t9o4R3ZVcw9TtjpeF84uA7+gI+TIqfnHN0p3T9PoAW2k4YzD9w
|
||||
yITn+i1GdFILwDTNUwUIcWbZtilquOVPIX6qVXXRwILwspVSihVhC9VBAoGBAL4Z
|
||||
fUfwxd5I1gtHh5OVUc3VieNNidvgbHTmzeJPO2KumFK0KnuXT/wV6QVAuwLPI+9a
|
||||
3pVRzIFDQPcZdXHBdYbXCFcpyndHqZKdbyQEmIs0gXsjpagg3mpaGedf4HBV1zE/
|
||||
rhh9BfGjd6eKLjCZ4ACguCni54ciNHgiLI/Ul+oJAoGAQMprKI4uPfAnvVJuEN20
|
||||
P8prsJpcudsgdDNazodKEWo6uhuqcpHF6aECgulSfrn6ewmt4aiLrzmiWXlC2z1z
|
||||
EXDKSdk+jA/7RJL+oLN4WYBI9qtA5tAdYbfcoJmZgB/jXdqkPe3aD/mdqn7NfxmG
|
||||
zIjGgAIFvv2yb0Oph3pGMXo=
|
||||
-----END PRIVATE KEY-----
|
21
certificates/snakeoil.pem
Normal file
21
certificates/snakeoil.pem
Normal file
|
@ -0,0 +1,21 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDbTCCAlWgAwIBAgIUcywFzfoAiMaUnAfJah7Yy3pq4rAwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yNTA3MTAxOTI5MjRaGA85OTk5
|
||||
MTIzMTE5MjkyNFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
|
||||
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBANzZiYb3S+Yb86DWGm5+7zViMNo80Y52wNyNqADS
|
||||
YUWzaQYBOuD3klk1y7kB5/yuikQhX2a7f77M/wpWM8P7scnZ4KRPW1PggDL2rglA
|
||||
AS/V5/KMdtx+BcCE9GGKXaFIgJLaUKcvR1M9UWT8+OPm2X69q3OiIsOadKlsROMg
|
||||
P50bsgFjE61WUfrVkQxXaNQecY9xl+/lQUxAPqaGpXVVLNM75fgSFPV9UhHO8zcD
|
||||
bVhsqh/fP0fHGV2LOGNXuQCKEGsP/aLUQM4BnAW259BUbwPLn6lSXbXFwF9yYAnw
|
||||
GrPkOTqPAKVFQxIa/5Y1v5EbtqfVSSzNWc8a/QYPrlSdUO0CAwEAAaNTMFEwHQYD
|
||||
VR0OBBYEFMFWyHV3/5i/Ue5HsCST/wLRPeOEMB8GA1UdIwQYMBaAFMFWyHV3/5i/
|
||||
Ue5HsCST/wLRPeOEMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
|
||||
AJ2sUw5r3JL8LnczTaiiyn36vuCh0eOlzKDadTH9Wk5QGYShKx8a8EcePJ4+l7yL
|
||||
0f5S9npxXCSRF4daG0BZNBQSTpGu/sT6hJ5/Knmpso8w2PWFPMaYhNi+6zQJ3Bno
|
||||
sfsJgoVsklUWMRuCVcoyLpAbc0UEb+uuDuLeQTdYP9PzmDp8/UUZBvJ/NznGrFZt
|
||||
aKnx/g6Qu0gdQKH5pGL3C707CxsvM54UXi5pswbs0kqql9oVTKsAukPeGMXl2num
|
||||
dSZy+yNAGCsuUGJhG0yatZh473nYYtV4fzzvPIorCrjjvada6Z8EM3RQBOmDT9Oc
|
||||
RRed5U4jJ3IRbYBF1Q8tagg=
|
||||
-----END CERTIFICATE-----
|
17
docker-compose.yml
Normal file
17
docker-compose.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
services:
|
||||
webserver:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Containerfile
|
||||
environment:
|
||||
DOMAIN: example.localhost
|
||||
SERVER_ID: development
|
||||
ACME_CHALLENGE_URL: http://localhost/acme-challenge
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "443:443/udp"
|
||||
volumes:
|
||||
- ./run/html:/var/www/html
|
||||
- ./run/certs:/etc/ssl/certs
|
||||
- ./run/reload:/var/run/nginx-reload
|
17
docker-entrypoint.d/10-initialize-certificates.sh
Executable file
17
docker-entrypoint.d/10-initialize-certificates.sh
Executable file
|
@ -0,0 +1,17 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ls -la /etc/ssl
|
||||
ls -la /etc/nginx
|
||||
|
||||
CERTIFICATE_ROOT="/etc/ssl"
|
||||
CERTIFICATE_DOMAIN_ROOT="$CERTIFICATE_ROOT/certs/$DOMAIN"
|
||||
|
||||
mkdir -p "$CERTIFICATE_DOMAIN_ROOT"
|
||||
|
||||
cp -n "$CERTIFICATE_ROOT/snakeoil.pem" "$CERTIFICATE_DOMAIN_ROOT/fullchain.pem"
|
||||
cp -n "$CERTIFICATE_ROOT/snakeoil.key" "$CERTIFICATE_DOMAIN_ROOT/privkey.pem"
|
||||
|
||||
chmod 700 "$CERTIFICATE_DOMAIN_ROOT/fullchain.pem"
|
||||
chmod 700 "$CERTIFICATE_DOMAIN_ROOT/privkey.pem"
|
7
docker-entrypoint.d/50-watch-reload.sh
Normal file
7
docker-entrypoint.d/50-watch-reload.sh
Normal file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
echo "Starting reload watcher..."
|
||||
|
||||
/opt/scripts/watch-reload.sh &
|
90
nginx/nginx.conf
Normal file
90
nginx/nginx.conf
Normal file
|
@ -0,0 +1,90 @@
|
|||
user nginx;
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent bytes "$http_referer" '
|
||||
'"$http_x_forwarded_for"';
|
||||
|
||||
# While I removed PII from the above log format, still better not logging
|
||||
access_log /dev/null main; # /var/log/nginx/access.log main;
|
||||
|
||||
|
||||
server_tokens off;
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
|
||||
quic_retry on;
|
||||
quic_gso on;
|
||||
ssl_early_data on; # READ https://blog.cloudflare.com/introducing-0-rtt/#whats-the-catch
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
gzip on;
|
||||
gzip_types *;
|
||||
gzip_min_length 1000;
|
||||
gzip_proxied any;
|
||||
|
||||
http2 on;
|
||||
|
||||
add_header Alt-Svc 'h3=":443"; ma=86400';
|
||||
add_header Strict-Transport-Security "max-age=63072000; preload" always;
|
||||
|
||||
# intermediate configuration
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ecdh_curve X25519:prime256v1:secp384r1;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
ssl_session_timeout 1h;
|
||||
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
|
||||
|
||||
# Make sure to generate it first
|
||||
ssl_dhparam /etc/ssl/dhparam.pem;
|
||||
|
||||
# OCSP stapling
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
|
||||
# async 'resolver' is important for proper operation of OCSP stapling
|
||||
resolver [2001:4860:4860::8888] 8.8.8.8;
|
||||
|
||||
# If certificates are marked OCSP Must-Staple, consider managing the
|
||||
# OCSP stapling cache with an external script, e.g. certbot-ocsp-fetcher
|
||||
|
||||
# HTTPS redirect / HSTS
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
# default HTTPS server
|
||||
server {
|
||||
listen 443 ssl default_server;
|
||||
listen 443 quic reuseport default_server;
|
||||
listen [::]:443 ssl default_server;
|
||||
|
||||
ssl_certificate /etc/ssl/snakeoil.pem;
|
||||
ssl_certificate_key /etc/ssl/snakeoil.key;
|
||||
|
||||
server_name _;
|
||||
|
||||
return 444;
|
||||
}
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
18
nginx/templates/default.conf.template
Normal file
18
nginx/templates/default.conf.template
Normal file
|
@ -0,0 +1,18 @@
|
|||
server {
|
||||
listen 443 ssl;
|
||||
listen 443 quic;
|
||||
listen [::]:443 ssl;
|
||||
listen [::]:443 quic;
|
||||
|
||||
server_name ${DOMAIN};
|
||||
|
||||
ssl_certificate /etc/ssl/certs/${DOMAIN}/fullchain.pem;
|
||||
ssl_certificate_key /etc/ssl/certs/${DOMAIN}/privkey.pem;
|
||||
|
||||
root /var/www/html/${DOMAIN};
|
||||
index index.html;
|
||||
|
||||
location .well-known/acme-challenge {
|
||||
proxy_pass ${ACME_CHALLENGE_URL};
|
||||
}
|
||||
}
|
5
scripts/reload.sh
Normal file
5
scripts/reload.sh
Normal file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
nginx -s reload
|
15
scripts/watch-reload.sh
Normal file
15
scripts/watch-reload.sh
Normal file
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
touch "$RELOAD_FILE"
|
||||
|
||||
# The loop will run once every time the file is saved.
|
||||
while inotifywait -e close_write "$RELOAD_FILE"; do
|
||||
echo "File '$RELOAD_FILE' changed. Reloading."
|
||||
if nginx -t; then
|
||||
nginx -s reload
|
||||
else
|
||||
echo "Nginx configuration is invalid. Skipping reload."
|
||||
fi
|
||||
done
|
Loading…
Add table
Add a link
Reference in a new issue