diff --git a/CHANGES b/CHANGES index da1dd3020..82e1090ae 100644 --- a/CHANGES +++ b/CHANGES @@ -2422,4 +2422,4 @@ * Update monaco-editor to 0.32.1 * Update xterm.js to 4.17.0 * Update docker to 20.10.12 - +* IPv6 support diff --git a/baseimage/initializeBaseUbuntuImage.sh b/baseimage/initializeBaseUbuntuImage.sh index 0cdde4957..85bd7d768 100755 --- a/baseimage/initializeBaseUbuntuImage.sh +++ b/baseimage/initializeBaseUbuntuImage.sh @@ -89,7 +89,7 @@ echo "==> Installing Docker" # create systemd drop-in file. if you channge options here, be sure to fixup installer.sh as well mkdir -p /etc/systemd/system/docker.service.d -echo -e "[Service]\nExecStart=\nExecStart=/usr/bin/dockerd -H fd:// --log-driver=journald --exec-opt native.cgroupdriver=cgroupfs --storage-driver=overlay2" > /etc/systemd/system/docker.service.d/cloudron.conf +echo -e "[Service]\nExecStart=\nExecStart=/usr/bin/dockerd -H fd:// --log-driver=journald --exec-opt native.cgroupdriver=cgroupfs --storage-driver=overlay2 --experimental --ip6tables" > /etc/systemd/system/docker.service.d/cloudron.conf # there are 3 packages for docker - containerd, CLI and the daemon readonly docker_version=20.10.12 diff --git a/setup/start.sh b/setup/start.sh index 1befc7947..6d9d7eb16 100755 --- a/setup/start.sh +++ b/setup/start.sh @@ -38,6 +38,13 @@ systemctl restart apparmor usermod ${USER} -a -G docker +if ! grep -q ip6tables /etc/systemd/system/docker.service.d/cloudron.conf; then + log "Adding ip6tables flag to docker" # https://github.com/moby/moby/pull/41622 + echo -e "[Service]\nExecStart=\nExecStart=/usr/bin/dockerd -H fd:// --log-driver=journald --exec-opt native.cgroupdriver=cgroupfs --storage-driver=overlay2 --experimental --ip6tables" > /etc/systemd/system/docker.service.d/cloudron.conf + systemctl daemon-reload + systemctl restart docker +fi + mkdir -p "${BOX_DATA_DIR}" mkdir -p "${APPS_DATA_DIR}" mkdir -p "${MAIL_DATA_DIR}" @@ -107,7 +114,7 @@ systemctl enable box systemctl enable cloudron-firewall systemctl enable --now cloudron-disable-thp -# update firewall rules +# update firewall rules. this must be done after docker created it's rules systemctl restart cloudron-firewall # For logrotate diff --git a/setup/start/cloudron-firewall.sh b/setup/start/cloudron-firewall.sh index c84ab5d52..03e65dcf7 100755 --- a/setup/start/cloudron-firewall.sh +++ b/setup/start/cloudron-firewall.sh @@ -3,6 +3,9 @@ set -eu -o pipefail echo "==> Setting up firewall" + +####### IPv4 + iptables -t filter -N CLOUDRON || true iptables -t filter -F CLOUDRON # empty any existing rules @@ -122,4 +125,23 @@ fi iptables -D FORWARD -j CLOUDRON_RATELIMIT || true iptables -I FORWARD 1 -j CLOUDRON_RATELIMIT +####### IPv6 + +# if file exists and has some content (despite being 0 size) +if cat /proc/net/if_inet6 >/dev/null 2>&1; then + echo "==> Setting up IPv6 firewall" + ip6tables -t filter -N CLOUDRON || true + ip6tables -t filter -F CLOUDRON # empty any existing rules + + ip6tables -t filter -A CLOUDRON -m state --state RELATED,ESTABLISHED -j ACCEPT + ip6tables -t filter -A CLOUDRON -p tcp -m tcp -m multiport --dports 22,80,202,443 -j ACCEPT # 202 is the alternate ssh port + + ip6tables -t filter -A CLOUDRON -m limit --limit 2/min -j LOG --log-prefix "IP6Tables Packet Dropped: " --log-level 7 + # ip6tables -t filter -A CLOUDRON -j DROP + + if ! ip6tables -t filter -C INPUT -j CLOUDRON 2>/dev/null; then + ip6tables -t filter -I INPUT -j CLOUDRON + fi +fi + echo "==> Setting up firewall done" diff --git a/src/docker.js b/src/docker.js index 0a857f49d..14f68ebbc 100644 --- a/src/docker.js +++ b/src/docker.js @@ -293,7 +293,7 @@ async function createSubcontainer(app, name, cmd, options) { exposedPorts[`${containerPort}/${portType}`] = {}; portEnv.push(`${portName}=${hostPort}`); - const hostIps = hostPort === 53 ? getAddresses() : [ '0.0.0.0' ]; // port 53 is special because it is possibly taken by systemd-resolved + const hostIps = hostPort === 53 ? getAddresses() : [ '0.0.0.0', '::0' ]; // port 53 is special because it is possibly taken by systemd-resolved dockerPortBindings[`${containerPort}/${portType}`] = hostIps.map(hip => { return { HostIp: hip, HostPort: hostPort + '' }; }); } diff --git a/src/infra_version.js b/src/infra_version.js index 2765a4146..c88630521 100644 --- a/src/infra_version.js +++ b/src/infra_version.js @@ -6,7 +6,7 @@ exports = module.exports = { // a version change recreates all containers with latest docker config - 'version': '48.20.0', + 'version': '49.0.0', 'baseImages': [ { repo: 'cloudron/base', tag: 'cloudron/base:3.2.0@sha256:ba1d566164a67c266782545ea9809dc611c4152e27686fd14060332dd88263ea' } diff --git a/src/platform.js b/src/platform.js index d6840205b..6fb6d1615 100644 --- a/src/platform.js +++ b/src/platform.js @@ -115,8 +115,9 @@ async function pruneInfraImages() { async function createDockerNetwork() { debug('createDockerNetwork: recreating docker network'); - await shell.promises.exec('createDockerNetwork', 'docker network rm cloudron'); - await shell.promises.exec('createDockerNetwork', 'docker network create --subnet=172.18.0.0/16 --ip-range=172.18.0.0/20 --gateway 172.18.0.1 cloudron'); + await shell.promises.exec('createDockerNetwork', 'docker network rm cloudron || true'); + // the --ipv6 option will work even in ipv6 is disabled. fd00 is IPv6 ULA + await shell.promises.exec('createDockerNetwork', 'docker network create --subnet=172.18.0.0/16 --ip-range=172.18.0.0/20 --gateway 172.18.0.1 --ipv6 --subnet=fd00:c107:d509::/64 cloudron'); } async function removeAllContainers() {