Linux LXC Host

From philcrump.co.uk
Jump to: navigation, search

These are my notes on setting up Linux as an LXC Host.

Webserver

echo "<new-hostname>" > /etc/hostname
hostname -F /etc/hostname
sed -i "s/127.0.1.1.*localhost/127.0.1.1\t<new-hostname>/g" /etc/hosts
mkdir .ssh
echo "<remote-user-ssh-key>" > .ssh/authorized_keys
apt update && apt -y dist-upgrade
reboot
...
apt-get autoremove

Install ufw

apt install ufw
ufw allow ssh
ufw logging off
ufw enable

Install nginx (ref: nginx.org)

14.04 Trusty:

echo "deb http://nginx.org/packages/mainline/ubuntu/ trusty nginx" > /etc/apt/sources.list.d/nginx.list
echo "deb-src http://nginx.org/packages/mainline/ubuntu/ trusty nginx" >> /etc/apt/sources.list.d/nginx.list
wget 'http://nginx.org/keys/nginx_signing.key' -O - | sudo apt-key add -
apt-get update
apt-get install nginx

16.04 Xenial:

echo "deb http://nginx.org/packages/mainline/ubuntu/ xenial nginx" > /etc/apt/sources.list.d/nginx.list
echo "deb-src http://nginx.org/packages/mainline/ubuntu/ xenial nginx" >> /etc/apt/sources.list.d/nginx.list
wget 'http://nginx.org/keys/nginx_signing.key' -O - | sudo apt-key add -
apt update
apt install nginx

Install mariadb (ref: mariadb.org)

14.04 Trusty:

echo "deb [arch=amd64,i386] http://lon1.mirrors.digitalocean.com/mariadb/repo/10.1/ubuntu trusty main" > /etc/apt/sources.list.d/mariadb.list
echo "deb-src http://lon1.mirrors.digitalocean.com/mariadb/repo/10.1/ubuntu trusty main" >> /etc/apt/sources.list.d/mariadb.list
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db
apt-get update
apt-get install mariadb-server

16.04 Xenial:

apt install software-properties-common
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
add-apt-repository 'deb [arch=amd64,i386,ppc64el] http://mirror.sax.uk.as61049.net/mariadb/repo/10.2/ubuntu xenial main'
apt update
apt install mariadb-server

Configure Mariadb

  • Comment out 'bind-address = ' in /etc/mysql/my.cnf to allow binding to non-loopback interface

Allow root login from LXCs

GRANT ALL PRIVILEGES ON *.* TO 'root'@'10.0.3.%' IDENTIFIED BY 'my-new-password' WITH GRANT OPTION;

Allow access to 3306 from LXCs

ufw allow from 10.0.3.1/24 proto udp to any port 3306

Configure nginx

Append to master config:

    error_log off;
    access_log off;
    index index.html;
    root /srv;
 
    sendfile        on;
    #tcp_nopush     on;
 
    keepalive_timeout  65;
 
    server_tokens off;
 
    gzip on;
    gzip_disable "msie6";
    gzip_vary on;
    gzip_comp_level 3;
    gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
 
    include /etc/nginx/conf.d/*.conf;
}

Example nginx config:

upstream pma {
    server 10.0.3.42;
}
server {
    listen 80;
    listen [::]:80;
 
    location / {
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_pass http://pma;
    }
}

Install lxc (ref: linuxcontainers.org)

14.04 Trusty:

add-apt-repository ppa:ubuntu-lxc/lxd-stable
apt-get update
apt-get dist-upgrade
apt-get install lxd
reboot
...
lxc remote add images images.linuxcontainers.org

16.04 Xenial: ...

Install system utils

apt-get install mosh htop
ufw allow mosh

Containers

To add a container and log in:

lxc launch images:ubuntu/trusty/amd64 container-name
lxc exec container-name -- /bin/bash

Barebones nginx install:

echo "deb http://nginx.org/packages/mainline/ubuntu/ trusty nginx" > /etc/apt/sources.list.d/nginx.list
echo "deb-src http://nginx.org/packages/mainline/ubuntu/ trusty nginx" >> /etc/apt/sources.list.d/nginx.list
wget 'http://nginx.org/keys/nginx_signing.key' -O - | sudo apt-key add -
apt-get update
apt-get install nginx

php install:

LC_ALL=en_US.UTF-8 add-apt-repository -y ppa:ondrej/php
apt-get update
apt-get install php5.6-fpm php5.6-mysql
# Optional extras:
apt-get install php5.6-gd
apt-get install php5.6-curl
apt-get install php5.6-mbstring
  • Change nginx to use 'www-data' user in /etc/nginx/nginx.conf'

mysql install:

echo "deb [arch=amd64,i386] http://lon1.mirrors.digitalocean.com/mariadb/repo/10.1/ubuntu trusty main" > /etc/apt/sources.list.d/mariadb.list
echo "deb-src http://lon1.mirrors.digitalocean.com/mariadb/repo/10.1/ubuntu trusty main" >> /etc/apt/sources.list.d/mariadb.list
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db
apt-get update
apt-get install mariadb-server

phpmyadmin

php dependencies: -mysql, -mbstring

wget 'https://files.phpmyadmin.net/phpMyAdmin/4.5.1/phpMyAdmin-4.5.1-all-languages.zip'
unzip phpMyAdmin-4.5.1-all-languages.zip
upstream php-fpm {
    server unix:/var/run/php5-fpm.sock;
}
server {
    listen 80 default;
 
    root   /srv/pma;
    access_log off;
    error_log off;
 
    index index.php index.html;
 
    location ~ [^/]\.php(/|$) {
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        if (!-f $document_root$fastcgi_script_name) {
            return 404;
        }
        fastcgi_param HTTP_PROXY "";
        fastcgi_pass    php-fpm;
        fastcgi_index   index.php;
        include         fastcgi_params;
        fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_hide_header 'X-Powered-By';
    }
}

opencart

Koken

php dependencies: -mysql, -gd, -curl

wordpress

nginx config (php5):

upstream php-fpm {
    server unix:/var/run/php5-fpm.sock;
}
server {
        listen 80 default;
 
        root   /srv/wordpress;
        access_log off;
        error_log off;
 
        index index.php index.html;
 
        location / {
                try_files $uri $uri/ /index.php?$args;
        }
 
        location ~ [^/]\.php(/|$) {
            fastcgi_split_path_info ^(.+?\.php)(/.*)$;
            if (!-f $document_root$fastcgi_script_name) {
                return 404;
            }
            fastcgi_pass    php-fpm;
            fastcgi_index   index.php;
            fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include         fastcgi_params;
            fastcgi_hide_header 'X-Powered-By';
        }
}

RTMP

apt-get update
apt-get install wget git build-essential libpcre3-dev libssl-dev
wget 'http://nginx.org/download/nginx-1.9.7.tar.gz'
tar -xzvf nginx-1.9.7.tar.gz
git clone https://github.com/arut/nginx-rtmp-module.git
cd nginx-1.9.7
./configure --add-module=/root/nginx-rtmp-module
make
make install
#!upstart
description "nginx rtmp server"
start on startup
stop on shutdown
respawn
script
  echo "Starting nginx-rtmp"
  cd {SERVER_DIRECTORY}
  exec /usr/local/nginx/sbin/nginx -c /usr/local/conf/nginx.conf
end script
post-stop exec sleep 2
apt-get update
sudo apt-get install autoconf automake build-essential libass-dev libfreetype6-dev \
  libtheora-dev libtool libvorbis-dev pkg-config texinfo zlib1g-dev
mkdir ffmpeg_sources
cd ~/ffmpeg_sources
# Install yasm
wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz
tar xzvf yasm-1.3.0.tar.gz
cd yasm-1.3.0
./configure --prefix="$HOME/ffmpeg_build" --bindir="$HOME/bin"
make
make install
make distclean
# Install x264
cd ~/ffmpeg_sources
wget http://download.videolan.org/pub/x264/snapshots/last_x264.tar.bz2
tar xjvf last_x264.tar.bz2
cd x264-snapshot*
PATH="$HOME/bin:$PATH" ./configure --prefix="$HOME/ffmpeg_build" --bindir="$HOME/bin" --enable-static
PATH="$HOME/bin:$PATH" make
make install
make distclean
# Install ffmpeg
cd ~/ffmpeg_sources
wget http://ffmpeg.org/releases/ffmpeg-snapshot.tar.bz2
tar xjvf ffmpeg-snapshot.tar.bz2
cd ffmpeg
PATH="$HOME/bin:$PATH" PKG_CONFIG_PATH="$HOME/ffmpeg_build/lib/pkgconfig" ./configure \
  --prefix="$HOME/ffmpeg_build" \
  --pkg-config-flags="--static" \
  --extra-cflags="-I$HOME/ffmpeg_build/include" \
  --extra-ldflags="-L$HOME/ffmpeg_build/lib" \
  --bindir="$HOME/bin" \
  --enable-gpl \
  --enable-libass \
  --enable-libfreetype \
  --enable-libtheora \
  --enable-libvorbis \
  --enable-libx264 \
  --enable-nonfree
PATH="$HOME/bin:$PATH" make
make install
make distclean
hash -r

Troubleshooting

LXC Container disappears

This is a very troubling issue. The container is missing from the `lxc list` and attempts to start it return errors about missing unix sockets.

The first related issue I found was ( https://github.com/lxc/lxd/issues/1405 ), noting the missing 'metadata.yaml' and 'templates/'. I therefore copied the 'metadata.yaml' file, and 'templates/' folder from another, fully functional, container on the host.

Following this, I rebooted the host. The container still did not appear in `lxc list` however starting it now returned a different error about "architecture '0' unsupported."

I then found this issue ( https://github.com/lxc/lxd/issues/1425 ) mentioning the same architecture error.

apt-get install sqlite3
sqlite3 /var/lib/lxd/lxd.db
sqlite3> UPDATE containers SET architecture=2 WHERE name="haproxy";

Following this, I was immediately able to see the container in `lxc list`, start it, and log in to it.

As of 22nd April 2017, I have not seen this issue again despite using several new LXD hosts.

Wordpress

Recommended Plugins:

  • TinyMCE Advanced - enables more options in editor
  • Google XML Sitemaps - Adds standards-compliant XML sitemaps
  • Configure SMTP - Allows use of external mail server

Nginx + PHP

sudo add-apt-repository ppa:ondrej/php
sudo apt update
sudo apt install php7.1-fpm php7.1-mysql php7.1-mbstring php7.1-gd
upstream php-fpm {
    server unix:/var/run/php/php7.1-fpm.sock;
}
...
  index index.php index.html;
 
  location / {
    try_files $uri $uri/ /index.php?$args;
  }
 
  location ~ [^/]\.php(/|$) {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    if (!-f $document_root$fastcgi_script_name) {
      return 404;
    }
    fastcgi_pass    php-fpm;
    fastcgi_index   index.php;
    fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include         fastcgi_params;
    fastcgi_hide_header 'X-Powered-By';
  }
}

Configure SMTP Troubleshooting

For some reason it fails during STARTTLS on my mailserver, which has a valid certificate. The only workaround I've found is to disable some of the cert checks.

Edit {wordpress}/wp-content/plugins/configure-smtp/configure-stmp.php

Look for:

        public function phpmailer_init( $phpmailer ) {
                $options = $this->get_options();
                // Don't configure for SMTP if no host is provided.
                if ( empty( $options['host'] ) )
                        return;
                $phpmailer->IsSMTP();
                $phpmailer->Host = $options['host'];
                $phpmailer->Port = $options['port'] ? $options['port'] : 25;
                $phpmailer->SMTPAuth = $options['smtp_auth'] ? $options['smtp_auth'] : false;
                if ( $phpmailer->SMTPAuth ) {
                        $phpmailer->Username = $options['smtp_user'];
                        $phpmailer->Password = $options['smtp_pass'];
                }
                if ( $options['smtp_secure'] != '' )
                        $phpmailer->SMTPSecure = $options['smtp_secure'];
                if ( $options['wordwrap'] > 0 )
                        $phpmailer->WordWrap = $options['wordwrap'];
                if ( $options['debug'] )
                        $phpmailer->SMTPDebug = true;
        }

Add the last section (disabling some cert checks)

        public function phpmailer_init( $phpmailer ) {
                $options = $this->get_options();
                // Don't configure for SMTP if no host is provided.
                if ( empty( $options['host'] ) )
                        return;
                $phpmailer->IsSMTP();
                $phpmailer->Host = $options['host'];
                $phpmailer->Port = $options['port'] ? $options['port'] : 25;
                $phpmailer->SMTPAuth = $options['smtp_auth'] ? $options['smtp_auth'] : false;
                if ( $phpmailer->SMTPAuth ) {
                        $phpmailer->Username = $options['smtp_user'];
                        $phpmailer->Password = $options['smtp_pass'];
                }
                if ( $options['smtp_secure'] != '' )
                        $phpmailer->SMTPSecure = $options['smtp_secure'];
                if ( $options['wordwrap'] > 0 )
                        $phpmailer->WordWrap = $options['wordwrap'];
                if ( $options['debug'] )
                        $phpmailer->SMTPDebug = true;
                $phpmailer->SMTPOptions = array(
                        'ssl' => array(
                                'verify_peer' => false,
                                'verify_peer_name' => false,
                                'allow_self_signed' => true
                        )
                );
        }

Behind Reverse Proxy

Wordpress likes to know the protocol and URL to set up it's resource URLs, and will aggressively redirect if these don't match what's configured.

So we use 'X-Forwarded-..' headers to pass through the information, and patch wordpress through the config file to set the PHP environment variables correctly.

Host nginx config:

location / {
                proxy_http_version 1.1;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto 'https';
                proxy_pass http://wordpress-server;
        }

Add to wp-config.php:

if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
    $_SERVER['HTTPS']='on';
 
if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_X_FORWARDED_FOR"];
}

MediaWiki

sudo add-apt-repository ppa:ondrej/php
sudo apt update
sudo apt install php7.1-fpm php7.1-mysql php7.1-mbstring php7.1-xml php7.1-gd php7.1-apcu php7.1-intl
upstream php-fpm {
  server unix:/var/run/php/php7.1-fpm.sock;
}
server {
  listen       80;
  access_log  off;
  #error_log  off;
  error_log /var/log/nginx/error.log;
 
  root /srv/wiki;
  client_max_body_size 8G;
 
  location / {
    index index.php index.html;
    try_files $uri $uri/ /index.php?title=$1;
  }
 
  location ^~ /images/ {
  }
  location ^~ /maintenance/ {
    deny all;
  }
  location ^~ /cache/ {
    deny all;
  }
 
  location ~ [^/]\.php(/|$) {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    if (!-f $document_root$fastcgi_script_name) {
      return 404;
    }
    fastcgi_pass    php-fpm;
    fastcgi_index   index.php;
    fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include         fastcgi_params;
    fastcgi_hide_header 'X-Powered-By';
    fastcgi_param   HTTPS       'On';
    fastcgi_param   SERVER_PORT 443;
    fastcgi_param REMOTE_ADDR $http_x_forwarded_for;
  }
}

Upgrading Mediawiki:

wget 'https://releases.wikimedia.org/mediawiki/1.26/mediawiki-1.26.3.patch.gz'
gzip -d mediawiki-1.26.3.patch.gz
# Test patching
sudo -u www-data patch -p1 --dry-run -i mediawiki-1.26.3.patch
# Run for real
sudo -u www-data patch -p1 -i mediawiki-1.26.3.patch
rm -v mediawiki-1.26.3.patch

Nodejs

14.04 Trusty:

wget -qO- https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -
echo 'deb https://deb.nodesource.com/node_6.x trusty main' > /etc/apt/sources.list.d/nodesource.list
echo 'deb-src https://deb.nodesource.com/node_6.x trusty main' >> /etc/apt/sources.list.d/nodesource.list
apt-get update
apt-get install nodejs

16.04 Xenial:

wget -qO- https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -
echo 'deb https://deb.nodesource.com/node_6.x xenial main' > /etc/apt/sources.list.d/nodesource.list
echo 'deb-src https://deb.nodesource.com/node_6.x xenial main' >> /etc/apt/sources.list.d/nodesource.list
apt update
apt install nodejs

Nginx-rtmp

sudo apt-get install build-essential libpcre3-dev libssl-dev
./configure --add-module=../nginx-rtmp-module/
make
sudo make install

Nextcloud

16.04 Xenial, PHP 7.0:

apt update && apt dist-upgrade
 
echo "deb http://nginx.org/packages/mainline/ubuntu/ xenial nginx" > /etc/apt/sources.list.d/nginx.list
echo "deb-src http://nginx.org/packages/mainline/ubuntu/ xenial nginx" >> /etc/apt/sources.list.d/nginx.list
wget 'http://nginx.org/keys/nginx_signing.key' -O - | sudo apt-key add -
apt update
apt install nginx
apt install php7.0-fpm php7.0-mysql php7.0-zip php7.0-xml php7.0-mbstring php7.0-gd php7.0-curl php7.0-intl
 
wget 'https://download.nextcloud.com/server/releases/nextcloud-11.0.2.zip'