#!/bin/sh -e # # A script to run the latest release version of the Let's Encrypt in a # virtual environment # # Installs and updates the letencrypt virtualenv, and runs letsencrypt # using that virtual environment. This allows the client to function decently # without requiring specific versions of its dependencies from the operating # system. # Note: you can set XDG_DATA_HOME or VENV_PATH before running this script, # if you want to change where the virtual environment will be installed XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN=${VENV_PATH}/bin # The path to the letsencrypt-auto script. Everything that uses these might # at some point be inlined... LEA_PATH=`dirname "$0"` BOOTSTRAP=${LEA_PATH}/bootstrap # This script takes the same arguments as the main letsencrypt program, but it # additionally responds to --verbose (more output) and --debug (allow support # for experimental platforms) for arg in "$@" ; do # This first clause is redundant with the third, but hedging on portability if [ "$arg" = "-v" ] || [ "$arg" = "--verbose" ] || echo "$arg" | grep -E -- "-v+$" ; then VERBOSE=1 elif [ "$arg" = "--debug" ] ; then DEBUG=1 fi done # letsencrypt-auto needs root access to bootstrap OS dependencies, and # letsencrypt itself needs root access for almost all modes of operation # The "normal" case is that sudo is used for the steps that need root, but # this script *can* be run as root (not recommended), or fall back to using # `su` if test "`id -u`" -ne "0" ; then if command -v sudo 1>/dev/null 2>&1; then SUDO=sudo else echo \"sudo\" is not available, will use \"su\" for installation steps... # Because the parameters in `su -c` has to be a string, # we need properly escape it su_sudo() { args="" # This `while` loop iterates over all parameters given to this function. # For each parameter, all `'` will be replace by `'"'"'`, and the escaped string # will be wrap in a pair of `'`, then append to `$args` string # For example, `echo "It's only 1\$\!"` will be escaped to: # 'echo' 'It'"'"'s only 1$!' # │ │└┼┘│ # │ │ │ └── `'s only 1$!'` the literal string # │ │ └── `\"'\"` is a single quote (as a string) # │ └── `'It'`, to be concatenated with the strings followed it # └── `echo` wrapped in a pair of `'`, it's totally fine for the shell command itself while [ $# -ne 0 ]; do args="$args'$(printf "%s" "$1" | sed -e "s/'/'\"'\"'/g")' " shift done su root -c "$args" } SUDO=su_sudo fi else SUDO= fi ExperimentalBootstrap() { # Arguments: Platform name, boostrap script name, SUDO command (iff needed) if [ "$DEBUG" = 1 ] ; then if [ "$2" != "" ] ; then echo "Bootstrapping dependencies for $1..." if [ "$3" != "" ] ; then "$3" "$BOOTSTRAP/$2" else "$BOOTSTRAP/$2" fi fi else echo "WARNING: $1 support is very experimental at present..." echo "if you would like to work on improving it, please ensure you have backups" echo "and then run this script again with the --debug flag!" exit 1 fi } DeterminePythonVersion() { if command -v python2.7 > /dev/null ; then export LE_PYTHON=${LE_PYTHON:-python2.7} elif command -v python27 > /dev/null ; then export LE_PYTHON=${LE_PYTHON:-python27} elif command -v python2 > /dev/null ; then export LE_PYTHON=${LE_PYTHON:-python2} elif command -v python > /dev/null ; then export LE_PYTHON=${LE_PYTHON:-python} else echo "Cannot find any Pythons... please install one!" fi PYVER=`$LE_PYTHON --version 2>&1 | cut -d" " -f 2 | cut -d. -f1,2 | sed 's/\.//'` if [ $PYVER -eq 26 ] ; then ExperimentalBootstrap "Python 2.6" elif [ $PYVER -lt 26 ] ; then echo "You have an ancient version of Python entombed in your operating system..." echo "This isn't going to work; you'll need at least version 2.6." exit 1 fi } # virtualenv call is not idempotent: it overwrites pip upgraded in # later steps, causing "ImportError: cannot import name unpack_url" if [ ! -d $VENV_PATH ] then if [ ! -f $BOOTSTRAP/debian.sh ] ; then echo "Cannot find the letsencrypt bootstrap scripts in $BOOTSTRAP" exit 1 fi if [ -f /etc/debian_version ] ; then echo "Bootstrapping dependencies for Debian-based OSes..." $SUDO $BOOTSTRAP/_deb_common.sh elif [ -f /etc/redhat-release ] ; then echo "Bootstrapping dependencies for RedHat-based OSes..." $SUDO $BOOTSTRAP/_rpm_common.sh elif `grep -q openSUSE /etc/os-release` ; then echo "Bootstrapping dependencies for openSUSE-based OSes..." $SUDO $BOOTSTRAP/_suse_common.sh elif [ -f /etc/arch-release ] ; then if [ "$DEBUG" = 1 ] ; then echo "Bootstrapping dependencies for Archlinux..." $SUDO $BOOTSTRAP/archlinux.sh else echo "Please use pacman to install letsencrypt packages:" echo "# pacman -S letsencrypt letsencrypt-apache" echo echo "If you would like to use the virtualenv way, please run the script again with the" echo "--debug flag." exit 1 fi elif [ -f /etc/manjaro-release ] ; then ExperimentalBootstrap "Manjaro Linux" manjaro.sh "$SUDO" elif [ -f /etc/gentoo-release ] ; then ExperimentalBootstrap "Gentoo" _gentoo_common.sh "$SUDO" elif uname | grep -iq FreeBSD ; then ExperimentalBootstrap "FreeBSD" freebsd.sh "$SUDO" elif uname | grep -iq Darwin ; then ExperimentalBootstrap "Mac OS X" mac.sh # homebrew doesn't normally run as root elif grep -iq "Amazon Linux" /etc/issue ; then ExperimentalBootstrap "Amazon Linux" _rpm_common.sh "$SUDO" else echo "Sorry, I don't know how to bootstrap Let's Encrypt on your operating system!" echo echo "You will need to bootstrap, configure virtualenv, and run a pip install manually" echo "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites" echo "for more info" fi DeterminePythonVersion echo "Creating virtual environment..." if [ "$VERBOSE" = 1 ] ; then virtualenv --no-site-packages --python $LE_PYTHON $VENV_PATH else virtualenv --no-site-packages --python $LE_PYTHON $VENV_PATH > /dev/null fi else DeterminePythonVersion fi printf "Updating letsencrypt and virtual environment dependencies..." if [ "$VERBOSE" = 1 ] ; then echo $VENV_BIN/pip install -U setuptools $VENV_BIN/pip install -U pip $VENV_BIN/pip install -r "$LEA_PATH"/py26reqs.txt -U letsencrypt letsencrypt-apache # nginx is buggy / disabled for now, but upgrade it if the user has # installed it manually if $VENV_BIN/pip freeze | grep -q letsencrypt-nginx ; then $VENV_BIN/pip install -U letsencrypt letsencrypt-nginx fi else $VENV_BIN/pip install -U setuptools > /dev/null printf . $VENV_BIN/pip install -U pip > /dev/null printf . # nginx is buggy / disabled for now... $VENV_BIN/pip install -r "$LEA_PATH"/py26reqs.txt > /dev/null printf . $VENV_BIN/pip install -U letsencrypt > /dev/null printf . $VENV_BIN/pip install -U letsencrypt-apache > /dev/null if $VENV_BIN/pip freeze | grep -q letsencrypt-nginx ; then printf . $VENV_BIN/pip install -U letsencrypt-nginx > /dev/null fi echo fi # Explain what's about to happen, for the benefit of those getting sudo # password prompts... echo "Running with virtualenv:" $SUDO $VENV_BIN/letsencrypt "$@" $SUDO $VENV_BIN/letsencrypt "$@"