Skip to content

Instantly share code, notes, and snippets.

@mathiasaerts
Last active December 30, 2018 22:48
Show Gist options
  • Save mathiasaerts/aa0ec400d96b3626d16ead7b8747d073 to your computer and use it in GitHub Desktop.
Save mathiasaerts/aa0ec400d96b3626d16ead7b8747d073 to your computer and use it in GitHub Desktop.
#!/bin/bash
#
# LXC Setup script
# ----------------
# This script aims to set up a simple container environment with
# an easy to use NAT network setup.
#
# It will install LXC as container runtime and set up dnsmasq as a
# simple DHCP server. LXC will be configured to create unpriviledged
# containers by default. The script will also configure a linux
# bridge to which the container's network interfaces can attach.
#
# created by Mathias Aerts <mathias-aerts.net> - 2018/12/30
#
#
# Requirements:
#
# - Debian based system
# - LXC 2.x
# Tested on a Debian Stretch VPS
#
#
# Usage:
#
# Execute this script as root. After that, follow the instructions
# below to set up your first container.
#
# In order to create a container, use the following commands:
#
# > lxc-create -t download -n <container name>
# or specify the image in the command line directly:
# > lxc-create -t download -n <container name> -- -d ubuntu -r xenial -a amd64
#
# By default, dnsmasq will assign an ip address from the configured
# range to the container. To ensure a container is given a static ip
# address (using DHCP), follow the steps below:
#
# - First we need to get the configured mac address for the container
# > grep hwaddr /var/lib/lxc/<container name>/config
#
# - Next, we'll add an entry in the dnsmasq config /etc/dnsmasq.d/containers.conf
# > dhcp-host=00:16:3e:xx:xx:xx,<container name>,10.100.1.10,45m
#
# - Restart dnsmasq service before starting the container
# > service dnsmasq restart
# > lxc-start -n <container name>
#
# Stop script when an error occurs
set -e
## Variables
# Networking
NET_BRIDGE='lxcbr0' # The name of the linux bridge we'll configure
NET_PREFIX='10.100.2' # Prefix for the network subnet you want to use (adjust other variables accordingly)
NET_HOST_IP="${NET_PREFIX}.1" # An ip address in the subnet for the host itself
NET_SUBNET="${NET_PREFIX}.0" # The network address
NET_CIDR="${NET_SUBNET}/24" # The subnet in CIDR notation
NET_MASK='255.255.255.0' # The subnet mask, should match the subnet address and CIDR notation above
NET_DHCP_START="${NET_PREFIX}.2" # Start of the DHCP range
NET_DHCP_END="${NET_PREFIX}.254" # End of the DHCP range
# Packages to install
PACKAGES=(
'vim'
'bash-completion'
'lxc'
'dnsmasq'
'curl'
'wget'
'ca-certificates'
'openssl'
'debootstrap'
'rsync'
'xz-utils'
'gnupg'
'dirmngr'
'bridge-utils'
'ifupdown'
)
# User and group
LXC_USER='lxcu'
LXC_GROUP="${LXC_USER}"
LXC_UID_GID_OFFSET=100000
# Config files
LXC_BASE_DIR='/var/lib/lxc'
NET_INTERFACES_FILE='/etc/network/interfaces'
LXC_DEFAULT_CONF='/etc/lxc/default.conf'
DNSMASQ_CONFIG_FILE='/etc/dnsmasq.d/lxc.conf'
## Start setup
# Install required packages
echo "* Updating package list.."
apt-get update >/dev/null 2>&1
echo "* Installing required packages.."
apt-get install -y ${PACKAGES[@]} >/dev/null 2>&1
# Write default LXC config
echo "* Writing default lxc config"
cat > "${LXC_DEFAULT_CONF}" <<EOF
# Container specific configuration
lxc.id_map = u 0 ${LXC_UID_GID_OFFSET} 65536
lxc.id_map = g 0 ${LXC_UID_GID_OFFSET} 65536
lxc.start.auto = 1
lxc.start.delay = 5
lxc.group = onboot
# Network configuration
lxc.network.type = veth
lxc.network.name = eth0
lxc.network.flags = up
lxc.network.link = ${NET_BRIDGE}
lxc.network.hwaddr = 00:16:3e:xx:xx:xx
EOF
# Add group and user for lxc
if ! grep -qE "^${LXC_GROUP}:" /etc/group; then
echo "* Adding group ${LXC_GROUP}"
groupadd -g "${LXC_UID_GID_OFFSET}" -r "${LXC_GROUP}"
fi
if ! grep -qE "^${LXC_USER}:" /etc/passwd; then
echo "* Adding user ${LXC_USER}"
useradd -d "${LXC_BASE_DIR}" -c "LXC Unpriviledged user" -M -r -s /bin/bash -u "${LXC_UID_GID_OFFSET}" -g "${LXC_GROUP}" "${LXC_USER}"
fi
# Set up network bridge
if ! grep -qE "^auto ${NET_BRIDGE}" "${NET_INTERFACES_FILE}"; then
echo "* Adding network bridge ${NET_BRIDGE}.."
cat >> "${NET_INTERFACES_FILE}" <<EOF
auto ${NET_BRIDGE}
iface ${NET_BRIDGE} inet static
address ${NET_HOST_IP}
netmask ${NET_MASK}
bridge_ports none
post-up echo 1 > /proc/sys/net/ipv4/ip_forward
post-up iptables -t nat -A POSTROUTING -s '${NET_CIDR}' -j MASQUERADE
post-down iptables -t nat -D POSTROUTING -s '${NET_CIDR}' -j MASQUERADE
EOF
fi
# Ensure bridge interface is up
# Run ifdown first to make sure we start clean
ifdown "${NET_BRIDGE}" >/dev/null 2>&1
ifup "${NET_BRIDGE}" >/dev/null 2>&1
# Write DHCP config
if ! [[ -e "${DNSMASQ_CONFIG_FILE}" ]]; then
echo "* Writing dnsmasq DHCP config.."
cat > "${DNSMASQ_CONFIG_FILE}" <<EOF
interface=${NET_BRIDGE}
except-interface=lo
dhcp-range=${NET_DHCP_START},${NET_DHCP_END},${NET_MASK},12h
EOF
fi
# Restart dnsmasq service
service dnsmasq restart
## Finished
echo "* All done. Create your first container using 'lxc-create -t download -n <container name>'"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment