Some update
This commit is contained in:
parent
c43a11fdd2
commit
e92a7e2e62
13 changed files with 94 additions and 128 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -1,2 +1,2 @@
|
||||||
run/
|
/run/
|
||||||
control-server/build/
|
/control-server/build/
|
||||||
76
.vscode/settings.json
vendored
76
.vscode/settings.json
vendored
|
|
@ -1,76 +0,0 @@
|
||||||
{
|
|
||||||
"files.associations": {
|
|
||||||
"ostream": "cpp",
|
|
||||||
"array": "cpp",
|
|
||||||
"atomic": "cpp",
|
|
||||||
"bit": "cpp",
|
|
||||||
"cctype": "cpp",
|
|
||||||
"charconv": "cpp",
|
|
||||||
"chrono": "cpp",
|
|
||||||
"clocale": "cpp",
|
|
||||||
"cmath": "cpp",
|
|
||||||
"codecvt": "cpp",
|
|
||||||
"compare": "cpp",
|
|
||||||
"concepts": "cpp",
|
|
||||||
"csignal": "cpp",
|
|
||||||
"cstdarg": "cpp",
|
|
||||||
"cstddef": "cpp",
|
|
||||||
"cstdint": "cpp",
|
|
||||||
"cstdio": "cpp",
|
|
||||||
"cstdlib": "cpp",
|
|
||||||
"cstring": "cpp",
|
|
||||||
"ctime": "cpp",
|
|
||||||
"cwchar": "cpp",
|
|
||||||
"cwctype": "cpp",
|
|
||||||
"deque": "cpp",
|
|
||||||
"string": "cpp",
|
|
||||||
"unordered_map": "cpp",
|
|
||||||
"vector": "cpp",
|
|
||||||
"exception": "cpp",
|
|
||||||
"algorithm": "cpp",
|
|
||||||
"functional": "cpp",
|
|
||||||
"iterator": "cpp",
|
|
||||||
"memory": "cpp",
|
|
||||||
"memory_resource": "cpp",
|
|
||||||
"numeric": "cpp",
|
|
||||||
"optional": "cpp",
|
|
||||||
"random": "cpp",
|
|
||||||
"ratio": "cpp",
|
|
||||||
"string_view": "cpp",
|
|
||||||
"system_error": "cpp",
|
|
||||||
"tuple": "cpp",
|
|
||||||
"type_traits": "cpp",
|
|
||||||
"utility": "cpp",
|
|
||||||
"format": "cpp",
|
|
||||||
"initializer_list": "cpp",
|
|
||||||
"iomanip": "cpp",
|
|
||||||
"iosfwd": "cpp",
|
|
||||||
"iostream": "cpp",
|
|
||||||
"istream": "cpp",
|
|
||||||
"limits": "cpp",
|
|
||||||
"new": "cpp",
|
|
||||||
"numbers": "cpp",
|
|
||||||
"ranges": "cpp",
|
|
||||||
"span": "cpp",
|
|
||||||
"sstream": "cpp",
|
|
||||||
"stdexcept": "cpp",
|
|
||||||
"streambuf": "cpp",
|
|
||||||
"typeinfo": "cpp",
|
|
||||||
"variant": "cpp",
|
|
||||||
"text_encoding": "cpp",
|
|
||||||
"queue": "cpp",
|
|
||||||
"filesystem": "cpp",
|
|
||||||
"any": "cpp",
|
|
||||||
"condition_variable": "cpp",
|
|
||||||
"coroutine": "cpp",
|
|
||||||
"source_location": "cpp",
|
|
||||||
"future": "cpp",
|
|
||||||
"mutex": "cpp",
|
|
||||||
"stop_token": "cpp",
|
|
||||||
"thread": "cpp",
|
|
||||||
"list": "cpp",
|
|
||||||
"semaphore": "cpp",
|
|
||||||
"stdfloat": "cpp",
|
|
||||||
"fstream": "cpp"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -24,12 +24,11 @@ RUN mkdir -p build \
|
||||||
|
|
||||||
FROM docker.io/nginx:${NGINX_TAG}
|
FROM docker.io/nginx:${NGINX_TAG}
|
||||||
|
|
||||||
ENV DOMAIN="example.localhost"
|
#ENV DOMAIN="example.localhost"
|
||||||
ENV SERVER_ID="server"
|
ENV SERVER_ID="server"
|
||||||
ENV RELOAD_FILE="/var/run/nginx-reload"
|
ENV ACME_CHALLENGE_URL='http://acme-challenge.${DOMAIN}/.well-known/acme-challenge'
|
||||||
ENV ACME_CHALLENGE_URL="http://acme-challenge.${DOMAIN}/.well-known/acme-challenge/"
|
#ENV CONTROL_DOMAIN="control.localhost"
|
||||||
ENV CONTROL_DOMAIN="control.localhost"
|
#ENV CONTROL_TOKEN="Tr0ub4dor&3"
|
||||||
ENV CONTROL_TOKEN="Tr0ub4dor&3"
|
|
||||||
|
|
||||||
COPY nginx /etc/nginx/
|
COPY nginx /etc/nginx/
|
||||||
COPY certificates /etc/ssl/
|
COPY certificates /etc/ssl/
|
||||||
|
|
|
||||||
28
README.md
28
README.md
|
|
@ -1,30 +1,30 @@
|
||||||
This is a container that helps host a static website.
|
This is a container that helps host a website.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
**Requires** the following mounts:
|
**Requires** the following mounts:
|
||||||
- `/etc/ssl/certs/$DOMAIN`: For certificates (`fullchain.pem` and `privkey.pem`)
|
- `/etc/ssl/certs/<domain>`: For certificates, `fullchain.pem` and `privkey.pem`. Also includes the control domain. Can be read-only if you don't use the built-in (control server) certificate management.
|
||||||
- `/var/www/html/$DOMAIN`: Website files, `index.html` goes right here
|
- `/var/www/html/<domain>`: Website files, `index.html` goes right here, mount this read-only
|
||||||
|
|
||||||
**Requires** the following environment variables:
|
**Requires** the following environment variables:
|
||||||
- `DOMAIN`: The domain
|
- `DOMAINS`: One or more domains to handle, separated with `,`s or spaces
|
||||||
- `ACME_CHALLENGE_HOST`: The source of `.well-known/acme-challenge`
|
- `ACME_CHALLENGE_HOST`: The source of `.well-known/acme-challenge`. Proxied, may be internal. Don't forget to add
|
||||||
|
- `CONTROL_DOMAIN`: Domain to access the control server
|
||||||
- `CONTROL_TOKEN`: Token to access the control server
|
- `CONTROL_TOKEN`: Token to access the control server
|
||||||
|
|
||||||
You're also encouraged to provide your own:
|
You're also encouraged to provide your own:
|
||||||
- `/etc/ssl/dhparam.pem`, generated with:
|
- `/etc/ssl/dhparam.pem` (read-only), generated with:
|
||||||
```bash
|
```bash
|
||||||
openssl dhparam -out dhparam.pem 4096
|
openssl dhparam -out dhparam.pem 4096
|
||||||
```
|
```
|
||||||
- `/etc/ssl/snakeoil.key` & `/etc/ssl/snakeoil.pem`, generated with:
|
- `/etc/ssl/snakeoil.key` (read-only) & `/etc/ssl/snakeoil.pem` (read-only), generated with:
|
||||||
```bash
|
```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"
|
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)
|
- `SERVER_ID`: Label this server (informational, not used currently)
|
||||||
- **Mount** `/var/run/nginx-reload`: modify this file to reload nginx
|
|
||||||
|
|
||||||
## Control server
|
## Control server
|
||||||
Authorize as you normally would with a Bearer token.
|
Authorize as you normally do with a Bearer token.
|
||||||
|
|
||||||
If you get an empty response, watch the status code!
|
If you get an empty response, watch the status code!
|
||||||
|
|
||||||
|
|
@ -41,5 +41,13 @@ Endpoints:
|
||||||
- `/reload`: Reloads nginx
|
- `/reload`: Reloads nginx
|
||||||
- `/certificate/<domain>`: Uploads a certificate (POST, upload like a form with field names `certificate` and `private_key`)
|
- `/certificate/<domain>`: Uploads a certificate (POST, upload like a form with field names `certificate` and `private_key`)
|
||||||
|
|
||||||
|
## Custom nginx configs
|
||||||
|
Put custom configuration templates in the `/templates/` directory
|
||||||
|
|
||||||
|
Stock config files, mount (read-only) to replace:
|
||||||
|
- Control: `control.conf.template` ([default](nginx/templates/control.conf.template))
|
||||||
|
- Website: `website.conf.btemplate` ([default](nginx/templates/website.conf.template)) (not used hence diff extension)
|
||||||
|
- Specific website: `website-$DOMAIN.conf.template` (generated)
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
- support for multiple domains
|
- support for multiple domains
|
||||||
|
|
@ -4,7 +4,7 @@ services:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Containerfile
|
dockerfile: Containerfile
|
||||||
environment:
|
environment:
|
||||||
DOMAIN: example.localhost
|
DOMAINS: example.localhost
|
||||||
SERVER_ID: development
|
SERVER_ID: development
|
||||||
ACME_CHALLENGE_URL: https://files.catbox.moe/xpfyfh
|
ACME_CHALLENGE_URL: https://files.catbox.moe/xpfyfh
|
||||||
CONTROL_DOMAIN: control.localhost
|
CONTROL_DOMAIN: control.localhost
|
||||||
|
|
@ -16,4 +16,5 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ./run/html:/var/www/html
|
- ./run/html:/var/www/html
|
||||||
- ./run/certs:/etc/ssl/certs
|
- ./run/certs:/etc/ssl/certs
|
||||||
- ./run/reload:/var/run/nginx-reload
|
|
||||||
|
|
||||||
17
docker-entrypoint.d/1-check-environment.sh
Normal file
17
docker-entrypoint.d/1-check-environment.sh
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
: "${DOMAINS?Error: DOMAINS environment variable is not set.}"
|
||||||
|
: "${CONTROL_DOMAIN?Error: CONTROL_DOMAIN environment variable is not set.}"
|
||||||
|
: "${CONTROL_TOKEN?Error: CONTROL_TOKEN environment variable is not set.}"
|
||||||
|
|
||||||
|
for domain in ${DOMAINS//,/ }; do
|
||||||
|
echo "Detected domain: $domain"
|
||||||
|
|
||||||
|
if [ "$domain" = "$CONTROL_DOMAIN" ]; then
|
||||||
|
echo "Domain must not equal control domain"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
14
docker-entrypoint.d/10-generate-templates.sh
Normal file
14
docker-entrypoint.d/10-generate-templates.sh
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [ -e "/templates" ]; then
|
||||||
|
cp -r templates/. /etc/nginx/templates/
|
||||||
|
fi
|
||||||
|
|
||||||
|
for domain in ${DOMAINS//,/ }; do
|
||||||
|
cp -n /etc/nginx/templates/website.conf.btemplate /etc/nginx/templates/website-$domain.conf.template
|
||||||
|
|
||||||
|
sed -i "s/\$DOMAIN/$domain/g" /etc/nginx/templates/website-$domain.conf.template
|
||||||
|
sed -i "s/\${DOMAIN}/$domain/g" /etc/nginx/templates/website-$domain.conf.template
|
||||||
|
done
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
|
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
: "${DOMAIN?Error: DOMAIN environment variable is not set.}"
|
|
||||||
: "${CONTROL_DOMAIN?Error: CONTROL_DOMAIN environment variable is not set.}"
|
|
||||||
|
|
||||||
CERTIFICATE_ROOT="/etc/ssl"
|
|
||||||
|
|
||||||
setup_snakeoil_cert() {
|
|
||||||
local domain="$1"
|
|
||||||
local cert_dir="$CERTIFICATE_ROOT/certs/$domain"
|
|
||||||
|
|
||||||
mkdir -p "$cert_dir"
|
|
||||||
|
|
||||||
cp -n "$CERTIFICATE_ROOT/snakeoil.pem" "$cert_dir/fullchain.pem"
|
|
||||||
cp -n "$CERTIFICATE_ROOT/snakeoil.key" "$cert_dir/privkey.pem"
|
|
||||||
|
|
||||||
chmod 644 "$cert_dir/fullchain.pem"
|
|
||||||
chmod 600 "$cert_dir/privkey.pem"
|
|
||||||
}
|
|
||||||
|
|
||||||
for domain_to_setup in "$DOMAIN" "$CONTROL_DOMAIN"; do
|
|
||||||
echo "Ensuring certificate for domain: $domain_to_setup"
|
|
||||||
setup_snakeoil_cert "$domain_to_setup"
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Placeholder certificate setup complete."
|
|
||||||
23
docker-entrypoint.d/5-initialize-certificates.sh
Executable file
23
docker-entrypoint.d/5-initialize-certificates.sh
Executable file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
CERTIFICATE_ROOT="/etc/ssl"
|
||||||
|
|
||||||
|
setup_snakeoil_cert() {
|
||||||
|
local domain="$1"
|
||||||
|
local cert_dir="$CERTIFICATE_ROOT/certs/$domain"
|
||||||
|
|
||||||
|
mkdir -p "$cert_dir"
|
||||||
|
|
||||||
|
cp -n "$CERTIFICATE_ROOT/snakeoil.key" "$cert_dir/privkey.pem"
|
||||||
|
cp -n "$CERTIFICATE_ROOT/snakeoil.pem" "$cert_dir/fullchain.pem"
|
||||||
|
|
||||||
|
chmod 600 "$cert_dir/privkey.pem" || true
|
||||||
|
chmod 600 "$cert_dir/fullchain.pem" || true
|
||||||
|
}
|
||||||
|
|
||||||
|
for domain in ${DOMAINS//,/ } $CONTROL_DOMAIN; do
|
||||||
|
echo "Ensuring certificate for domain: $domain"
|
||||||
|
setup_snakeoil_cert "$domain"
|
||||||
|
done
|
||||||
|
|
@ -6,4 +6,6 @@ CONTROL_SERVER_SOCKET="/var/run/control-server.sock"
|
||||||
NGINX_PID_FILE="/var/run/nginx.pid"
|
NGINX_PID_FILE="/var/run/nginx.pid"
|
||||||
CERTIFICATE_PATH="/etc/ssl/certs"
|
CERTIFICATE_PATH="/etc/ssl/certs"
|
||||||
|
|
||||||
|
# TODO run this as user
|
||||||
|
|
||||||
control_server $CONTROL_SERVER_SOCKET $NGINX_PID_FILE $CERTIFICATE_PATH &
|
control_server $CONTROL_SERVER_SOCKET $NGINX_PID_FILE $CERTIFICATE_PATH &
|
||||||
|
|
@ -13,9 +13,9 @@ http {
|
||||||
include /etc/nginx/mime.types;
|
include /etc/nginx/mime.types;
|
||||||
default_type application/octet-stream;
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
# looking for $remote_addr and $http_user_agent?
|
||||||
log_format main '$remote_user [$time_local] "$request" '
|
log_format main '$remote_user [$time_local] "$request" '
|
||||||
'$status $body_bytes_sent bytes "$http_referer" '
|
'$status $body_bytes_sent bytes "$http_referer" ';
|
||||||
'"$http_x_forwarded_for"';
|
|
||||||
|
|
||||||
access_log /var/log/nginx/access.log main; # /dev/null to disable
|
access_log /var/log/nginx/access.log main; # /dev/null to disable
|
||||||
|
|
||||||
|
|
@ -57,7 +57,7 @@ http {
|
||||||
ssl_stapling_verify on;
|
ssl_stapling_verify on;
|
||||||
|
|
||||||
# async 'resolver' is important for proper operation of OCSP stapling
|
# async 'resolver' is important for proper operation of OCSP stapling
|
||||||
resolver [2001:4860:4860::8888] 8.8.8.8;
|
# resolver [2001:4860:4860::8888] 8.8.8.8;
|
||||||
|
|
||||||
# If certificates are marked OCSP Must-Staple, consider managing the
|
# If certificates are marked OCSP Must-Staple, consider managing the
|
||||||
# OCSP stapling cache with an external script, e.g. certbot-ocsp-fetcher
|
# OCSP stapling cache with an external script, e.g. certbot-ocsp-fetcher
|
||||||
|
|
|
||||||
|
|
@ -18,4 +18,10 @@ server {
|
||||||
|
|
||||||
proxy_pass http://unix:/var/run/control-server.sock;
|
proxy_pass http://unix:/var/run/control-server.sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge {
|
||||||
|
set $target ${ACME_CHALLENGE_URL};
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_pass $target;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -13,7 +13,8 @@ server {
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
location /.well-known/acme-challenge {
|
location /.well-known/acme-challenge {
|
||||||
|
set $target ${ACME_CHALLENGE_URL};
|
||||||
proxy_buffering off;
|
proxy_buffering off;
|
||||||
proxy_pass ${ACME_CHALLENGE_URL};
|
proxy_pass $target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue