mirror of
https://github.com/nextcloud/all-in-one.git
synced 2025-02-26 06:43:16 +08:00
Merge pull request #3243 from nextcloud/ha-proxy-update
This commit is contained in:
commit
5b94e833bd
5 changed files with 72 additions and 103 deletions
|
@ -1,43 +1,17 @@
|
||||||
# Inspiration: https://github.com/Tecnativa/docker-socket-proxy/blob/master/Dockerfile
|
|
||||||
FROM haproxy:2.8.2-alpine3.18
|
FROM haproxy:2.8.2-alpine3.18
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
|
ENV NEXTCLOUD_HOST nextcloud-aio-nextcloud
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
apk add --no-cache tzdata; \
|
apk add --no-cache \
|
||||||
chmod 777 -R /run/; \
|
ca-certificates \
|
||||||
chmod 777 -R /var/lib/haproxy
|
tzdata \
|
||||||
|
bind-tools; \
|
||||||
|
chmod -R 777 /tmp
|
||||||
|
|
||||||
EXPOSE 2375
|
COPY --chmod=775 *.sh /
|
||||||
ENV ALLOW_RESTARTS=1 \
|
COPY --chmod=664 haproxy.cfg /haproxy.cfg
|
||||||
AUTH=1 \
|
|
||||||
BUILD=0 \
|
|
||||||
COMMIT=0 \
|
|
||||||
CONFIGS=0 \
|
|
||||||
CONTAINERS=1 \
|
|
||||||
DISTRIBUTION=0 \
|
|
||||||
EVENTS=0 \
|
|
||||||
EXEC=0 \
|
|
||||||
GRPC=0 \
|
|
||||||
IMAGES=1 \
|
|
||||||
INFO=1 \
|
|
||||||
LOG_LEVEL=info \
|
|
||||||
NETWORKS=1 \
|
|
||||||
NODES=0 \
|
|
||||||
PING=1 \
|
|
||||||
PLUGINS=0 \
|
|
||||||
POST=1 \
|
|
||||||
SECRETS=0 \
|
|
||||||
SERVICES=0 \
|
|
||||||
SESSION=0 \
|
|
||||||
SOCKET_PATH=/var/run/docker.sock \
|
|
||||||
SWARM=0 \
|
|
||||||
SYSTEM=0 \
|
|
||||||
TASKS=0 \
|
|
||||||
VERSION=1 \
|
|
||||||
VOLUMES=1
|
|
||||||
COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
|
|
||||||
|
|
||||||
USER root
|
ENTRYPOINT ["/start.sh"]
|
||||||
|
HEALTHCHECK CMD /healthcheck.sh
|
||||||
HEALTHCHECK CMD nc -z 127.0.0.1 2375 || exit 1
|
LABEL com.centurylinklabs.watchtower.enable="false"
|
||||||
|
|
|
@ -1,72 +1,41 @@
|
||||||
# Inspiration: https://github.com/Tecnativa/docker-socket-proxy/blob/master/haproxy.cfg
|
# Inspiration: https://github.com/Tecnativa/docker-socket-proxy/blob/master/haproxy.cfg
|
||||||
|
|
||||||
global
|
|
||||||
log stdout format raw daemon "${LOG_LEVEL}"
|
|
||||||
|
|
||||||
pidfile /run/haproxy.pid
|
|
||||||
maxconn 4000
|
|
||||||
|
|
||||||
# Turn on stats unix socket
|
|
||||||
# server-state-file /var/lib/haproxy/server-state
|
|
||||||
|
|
||||||
defaults
|
defaults
|
||||||
mode http
|
|
||||||
log global
|
|
||||||
option httplog
|
|
||||||
option dontlognull
|
|
||||||
option http-server-close
|
|
||||||
option redispatch
|
|
||||||
retries 3
|
|
||||||
timeout http-request 10s
|
|
||||||
timeout queue 1m
|
|
||||||
timeout connect 10s
|
timeout connect 10s
|
||||||
timeout client 10m
|
timeout client 10s
|
||||||
timeout server 10m
|
timeout server 10s
|
||||||
timeout http-keep-alive 10s
|
|
||||||
timeout check 10s
|
|
||||||
maxconn 3000
|
|
||||||
|
|
||||||
# Allow seamless reloads
|
frontend http
|
||||||
# load-server-state-from-file global
|
mode http
|
||||||
|
|
||||||
# Use provided example error pages
|
|
||||||
errorfile 400 /usr/local/etc/haproxy/errors/400.http
|
|
||||||
errorfile 403 /usr/local/etc/haproxy/errors/403.http
|
|
||||||
errorfile 408 /usr/local/etc/haproxy/errors/408.http
|
|
||||||
errorfile 500 /usr/local/etc/haproxy/errors/500.http
|
|
||||||
errorfile 502 /usr/local/etc/haproxy/errors/502.http
|
|
||||||
errorfile 503 /usr/local/etc/haproxy/errors/503.http
|
|
||||||
errorfile 504 /usr/local/etc/haproxy/errors/504.http
|
|
||||||
|
|
||||||
backend dockerbackend
|
|
||||||
server dockersocket $SOCKET_PATH
|
|
||||||
|
|
||||||
frontend dockerfrontend
|
|
||||||
bind :2375
|
bind :2375
|
||||||
http-request deny unless METH_GET || { env(POST) -m bool }
|
http-request deny unless { src 127.0.0.1 } || { src ::1 } || { src NC_IPV4_PLACEHOLDER } || { src NC_IPV6_PLACEHOLDER }
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/[a-zA-Z0-9_.-]+/((stop)|(restart)|(kill)) } { env(ALLOW_RESTARTS) -m bool }
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/nc_app_[a-zA-Z0-9_.-]+/((json)|(start)|(stop)) } METH_GET
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/auth } { env(AUTH) -m bool }
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/nc_app_[a-zA-Z0-9_.-]+ } METH_DELETE
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/build } { env(BUILD) -m bool }
|
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/commit } { env(COMMIT) -m bool }
|
# ACL to restrict container name to nc_app_[a-zA-Z0-9_.-]+
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/configs } { env(CONFIGS) -m bool }
|
acl nc_app_container_name url_param(name) -m reg -i "^nc_app_[a-zA-Z0-9_.-]+"
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers } { env(CONTAINERS) -m bool }
|
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/distribution } { env(DISTRIBUTION) -m bool }
|
# ACL to restrict the number of Mounts to 1
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/events } { env(EVENTS) -m bool }
|
acl one_mount_volume req.body -m reg -i "\"Mounts\"\s*:\s*\[\s*(?:(?!\"Mounts\"\s*:\s*\[)[^}]*)}[^}]*\]"
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/exec } { env(EXEC) -m bool }
|
# ACL to deny if there are any binds
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/grpc } { env(GRPC) -m bool }
|
acl binds_present req.body -m reg -i "\"HostConfig\"\s*:.*\"Binds\"\s*:"
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/images } { env(IMAGES) -m bool }
|
# ACL to restrict the type of Mounts to volume
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/info } { env(INFO) -m bool }
|
acl type_not_volume req.body -m reg -i "\"Mounts\":\s*\[[^\]]*(\"Type\":\s*\"(?!volume\b)\w+\"[^\]]*)+\]"
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/networks } { env(NETWORKS) -m bool }
|
http-request deny if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/create } nc_app_container_name !one_mount_volume binds_present type_not_volume METH_POST
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/nodes } { env(NODES) -m bool }
|
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/_ping } { env(PING) -m bool }
|
# ACL to restrict container creation, that it has HostConfig.Privileged only set to false
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/plugins } { env(PLUGINS) -m bool }
|
acl no_privileged_flag req.body -m reg -i "\"HostConfig\":\s?{[^}]*\"Privileged\":\s?false"
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/secrets } { env(SECRETS) -m bool }
|
# ACL to allow mount volume with strict pattern for name: nc_app_[a-zA-Z0-9_.-]+_data
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/services } { env(SERVICES) -m bool }
|
acl nc_app_volume_data_only req.body -m reg -i "\"Mounts\":\s?\[\s?{[^}]*\"Source\":\s?\"nc_app_[a-zA-Z0-9_.-]+_data\""
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/session } { env(SESSION) -m bool }
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/create } nc_app_container_name no_privileged_flag nc_app_volume_data_only METH_POST
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/swarm } { env(SWARM) -m bool }
|
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/system } { env(SYSTEM) -m bool }
|
acl nc_app_volume_data req.body -m reg -i "\"Name\":\s?\"nc_app_[a-zA-Z0-9_.-]+_data\""
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/tasks } { env(TASKS) -m bool }
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/volumes/create } nc_app_volume_data METH_POST
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/version } { env(VERSION) -m bool }
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/volumes/nc_app_[a-zA-Z0-9_.-]+_data } METH_DELETE
|
||||||
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/volumes } { env(VOLUMES) -m bool }
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/images/create } METH_POST
|
||||||
http-request deny
|
http-request deny
|
||||||
default_backend dockerbackend
|
default_backend dockerbackend
|
||||||
|
|
||||||
|
backend dockerbackend
|
||||||
|
mode http
|
||||||
|
server dockersocket /var/run/docker.sock
|
||||||
|
|
6
Containers/docker-socket-proxy/healthcheck.sh
Normal file
6
Containers/docker-socket-proxy/healthcheck.sh
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
nc -z "$NEXTCLOUD_HOST" 9000 || exit 0
|
||||||
|
if [ "$(wget http://127.0.0.1:2375/v1.41/_ping -qO -)" != "OK" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
21
Containers/docker-socket-proxy/start.sh
Normal file
21
Containers/docker-socket-proxy/start.sh
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Only start container if nextcloud is accessible
|
||||||
|
while ! nc -z "$NEXTCLOUD_HOST" 9000; do
|
||||||
|
echo "Waiting for Nextcloud to start..."
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
set -x
|
||||||
|
IPv4_ADDRESS_NC="$(dig nextcloud-aio-nextcloud IN A +short | grep '^[0-9.]\+$' | sort | head -n1)"
|
||||||
|
HAPROXYFILE="$(sed "s|NC_IPV4_PLACEHOLDER|$IPv4_ADDRESS_NC|" /haproxy.cfg)"
|
||||||
|
echo "$HAPROXYFILE" > /tmp/haproxy.cfg
|
||||||
|
|
||||||
|
IPv6_ADDRESS_NC="$(dig nextcloud-aio-nextcloud AAAA +short | grep '^[0-9a-f:]\+$' | sort | head -n1)"
|
||||||
|
HAPROXYFILE="$(sed "s# || { src NC_IPV6_PLACEHOLDER }##g" /tmp/haproxy.cfg)"
|
||||||
|
# shellcheck disable=SC2001
|
||||||
|
HAPROXYFILE="$(echo "$HAPROXYFILE" | sed "s|NC_IPV6_PLACEHOLDER|$IPv6_ADDRESS_NC|")"
|
||||||
|
echo "$HAPROXYFILE" > /tmp/haproxy.cfg
|
||||||
|
set +x
|
||||||
|
|
||||||
|
haproxy -f /tmp/haproxy.cfg -db
|
|
@ -661,8 +661,7 @@
|
||||||
"restart": "unless-stopped",
|
"restart": "unless-stopped",
|
||||||
"read_only": true,
|
"read_only": true,
|
||||||
"tmpfs": [
|
"tmpfs": [
|
||||||
"/run/",
|
"/tmp"
|
||||||
"/var/lib/haproxy"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in a new issue