Containers – SSD Nodes https://www.ssdnodes.com VPS Cloud Hosting For Hundreds Less Sun, 18 May 2025 20:03:05 +0000 en-US hourly 1 https://wordpress.org/?v=6.7.1 https://www.ssdnodes.com/wp-content/uploads/2024/09/fav.svg Containers – SSD Nodes https://www.ssdnodes.com 32 32 How To Remove Docker Images, Containers, and Volumes https://www.ssdnodes.com/blog/how-to-remove-docker-images-containers-and-volumes/ https://www.ssdnodes.com/blog/how-to-remove-docker-images-containers-and-volumes/#respond Tue, 04 Apr 2023 09:03:13 +0000 https://blog.ssdnodes.com/blog/?p=7431 Docker is an open-source platform for developing, shipping, and running applications. It is designed to make it easier to create, deploy, and run applications by using containers. With Docker, developers can package their applications into standardized units called containers, which can then be run on any computer, regardless of the operating system or hardware.

Docker allows developers to quickly and easily deploy their applications in a consistent environment, without having to worry about the underlying infrastructure. Docker also provides a rich set of tools and services for managing and monitoring applications, as well as for building and sharing images with other developers. Docker is an essential tool for modern software development, and it is used by many of the world's leading companies.

In this tutorial, you’ll learn how to remove Docker images, containers, and volumes to free up disk space on your system.

Prerequisites

  • Basic knowledge of the Linux command line.
  • An Ubuntu 22.04 server with a non-root user with sudo privileges. You can get affordable, and powerful Ubuntu servers from our website, and you can check out our How to access your server using SSH guide to learn how to access your server and create a sudo user.
  • Docker installed on your server. See How To Install and Use Docker on Ubuntu 22.04 to learn how to install Docker and use it to download images and run containers.

Pulling a Few Images from Docker Hub

Docker Hub is a cloud-based service that provides a centralized repository for Docker images. It allows users to store, manage, and share Docker images with other users. It provides a secure and reliable way to share and store Docker images, which can be used to create and deploy applications. Docker Hub also provides a wide range of services, such as private repositories, automated builds, and integration with other services.

To test whether you can access Docker Hub, run the hello-world image:

sudo docker run hello-world

You should receive an output that shows that your installation is working correctly:

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete 
Digest: sha256:c77be1d3a47d0caf71a82dd893ee61ce01f32fc758031a6ec4cf1389248bb833
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

To demonstrate how to remove images and containers, we will first download a few images and use them to run containers.

For example, run the following command to download the official Ubuntu image:

sudo docker pull ubuntu

You can also download the official Debian image like so:

sudo docker pull debian

Next, to demonstrate how to remove a actively running container, we will download the official nginx image and run a container using it:

sudo docker pull nginx

Run a Nginx container and call it docker-nginx using the following command:

sudo docker run --name docker-nginx -p 80:80 -d nginx

You should receive the container's ID as an output.

Next, run a container using the Ubuntu image you've downloaded previously with an interactive shell using the docker run and the -it switches:

sudo docker run -it ubuntu

Your prompt should now be a root shell like so:

root@242d22e1d9da:/#

Exit from it using the following command:

exit

With this, the Ubuntu container will have a status of Exited. Next, you'll learn how to list and remove images and containers.

Listing Images and Containers

You can list the images you've downloaded so far using the following command:

sudo docker images

You should see a list of the images you've downloaded so far:

REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
nginx         latest    3964ce7b8458   5 days ago      142MB
ubuntu        latest    6b7dfa7e8fdb   10 days ago     77.8MB
debian        latest    291bf168077c   13 days ago     124MB
hello-world   latest    feb5d9fea6a5   15 months ago   13.3kB

To list the containers you have on your system, use the following command:

sudo docker container ls -a

You should receive a table that shows a list of containers and information on each one of them, similar to the following:

CONTAINER ID   IMAGE         COMMAND                  CREATED        STATUS                    PORTS                               NAMES
fe965bef3738   ubuntu        "bash"                   27 hours ago   Exited (0) 27 hours ago                                       unruffled_wright
d509c583954b   nginx         "/docker-entrypoint.…"   27 hours ago   Up 27 hours               0.0.0.0:80->80/tcp, :::80->80/tcp   docker-nginx
434eb7e61fab   ubuntu        "bash"                   27 hours ago   Exited (0) 27 hours ago                                       jolly_jones
c199b4904b1f   nginx         "/docker-entrypoint.…"   27 hours ago   Exited (0) 27 hours ago                                       festive_newton

You will need the container ID to remove a container, so take note of it.

Removing a Docker Container

To remove a docker container, use the docker container rm command and pass it the ID of the container you wish to remove, or multiple container IDs if you wish to remove multiple ones. For example, to delete the first container in the previous list, run the following command:

sudo docker container rm fe965bef3738

You should receive the container ID as an output. Check that the container is properly removed by listing your containers:

sudo docker container ls -a

The Ubuntu container with the ID fe965bef3738 should no longer be in the list.

You can remove multiple containers at once by passing multiple container IDs to the docker container rm command like so:

docker container rm dbc6a1c52dbf 242d22e1d9da

If you attempt to remove a running container, such as the docker-nginx container, you will receive an error message similar to the following:

Error response from daemon: You cannot remove a running container d509c583954b31eb02bd26a9c8f2cf832d5213020362f89d1999c097ef64a98d. Stop the container before attempting removal or force remove

As you can see in the error message, you need to stop any running containers before removing them.

To stop a container, use the docker container stop command:

sudo docker container stop d509c583954b

Once stopped, you can remove it using docker container rm.

To remove all stopped containers at once, use the docker container prune command:

sudo docker container prune

This should output a warning, and a prompt for confirmation, once you confirm, a list of the removed containers will be displayed with the total cleared up space:

WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
434eb7e61fabc5707717bc12433615b4bd0b42766f5a51c7d6f506c6fb1f9bbf
c199b4904b1f20509170f56403141db9c3996aa7b6eeb3155837d10a5d8d0b08
dbc6a1c52dbfe7e92bc920dd2565383b30e827782943487b9e00f41435916f57
a7c5f7b98198361524d6f5904ee8b299c7901968327dee87ca76dcc73f79fdf6
242d22e1d9da87f49da95b047eecc6d0f41bb6ba8cb6cec6e5e89835323f5608
4aa674aadcdd96d98ae783c8d85625486ff98e44f9a4b9c99fb6c24de1e4b6e2

Total reclaimed space: 70.15MB

Listing and Removing Docker Images

As previously demonstrated, to list all the downloaded Docker images, you can use the following command:

sudo docker images

This should display a list of the images you've downloaded so far in a table similar to the following:

REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
nginx         latest    3964ce7b8458   8 days ago      142MB
ubuntu        latest    6b7dfa7e8fdb   13 days ago     77.8MB
debian        latest    291bf168077c   2 weeks ago     124MB
hello-world   latest    feb5d9fea6a5   15 months ago   13.3kB

To remove a Docker image, pass its ID to the docker image rm command like so:

sudo docker image rm 6b7dfa7e8fdb

You can also remove multiple images at once by passing multiple IDs to the docker image rm like so:

sudo docker image rm 291bf168077c 3964ce7b8458

To remove all dangling and unused images, use the docker image prune command with the -a flag to remove both untagged and unused images:

sudo docker image prune -a

Listing and Removing Docker Volumes

In a similar way to containers and images, you can use the docker volume ls to list Docker volumes in your system:

sudo docker volume ls

If you have Docker volumes on your system, you should receive a list of volumes like so:

DRIVER    VOLUME NAME
local     basic
local     faa5ac67cf1325d03b01c72f56749d3f1a8010fd6db24d8683b490c8819d775e

To remove a volume, pass its VOLUME NAME to the docker volume rm command like so:

sudo docker volume rm faa5ac67cf1325d03b01c72f56749d3f1a8010fd6db24d8683b490c8819d775e

If a container is actively using the volume you wish to remove, you'll receive an error message similar to the following:

Error response from daemon: remove faa5ac67cf1325d03b01c72f56749d3f1a8010fd6db24d8683b490c8819d775e: volume is in use - [da5fdeaad32aa66b6f7f2a8da8b21b5477dd217fc46340d711476f96707ede58]

To fix this, make sure to remove the container that uses the volume you wish to remove first.

To remove all unused volumes, use the docker volume prune command like so:

sudo docker volume prune

Removing Unused Docker Containers, Images, and Networks

To remove all unused Docker objects at once, such as all stopped containers, dangling images, unused networks, and all build cache, use the following command:

docker system prune -a

This should display the following warning:

WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all images without at least one container associated to them
  - all build cache

Are you sure you want to continue? [y/N]

This lists all the Docker objects that will be removed, confirm the process by typing y then ENTER.

Note that the previous command does not remove unused volumes to prevent accidental data loss. To also remove unused volumes, use the following command:

docker system prune --volumes

Conclusion

With this, you can now clean up your system by removing unwanted Docker objects, such as unused images, unused stopped containers, and unused volumes. Check out the Docker guides for more information on Docker.

]]>
https://www.ssdnodes.com/blog/how-to-remove-docker-images-containers-and-volumes/feed/ 0
My server setup: Ranvir Singh and Linux containers https://www.ssdnodes.com/blog/server-setup-ranvir/ https://www.ssdnodes.com/blog/server-setup-ranvir/#respond Thu, 27 Sep 2018 18:19:59 +0000 https://blog.ssdnodes.com/blog/?p=2748

Over the next few weeks, we're going to be exploring how a few of our team members set up brand-new servers of their own. These aren't meant to be tutorials, but rather fun investigations into the near-infinite ways we can accomplish the same task.

If you'd like to be featured in a future edition, feel free to let me know: joel@ssdnodes.com.


We all have our particular setups, applications we install, and services we run to keep our servers well-organized and secure. Today, I wanted to talk about a few things I do when starting with a new server.

Updates and security

The first thing I presume we all do is run apt update && apt upgrade -y, or a similar command for the package manager on your distro. After this, I try my luck with apt autoremove which, gets rid of some the unwanted files and packages that I won’t need.

Notice how I didn’t mention sudo in the above commands… that’s because when I first log in to my VPS, I’m logged in as the omnipotent root user. What’s worse is that I’m logged in as root user over SSH! Not good. So, my next step involves changing a few things about my server:

  1. Create a new user with root privileges.
  2. Make sure that the new user can log in over SSH using a public-private key pair.
  3. Make sure that root user can’t login over SSH.
  4. Block unnecessary ports.

The order of this checklist is essential!

1. Create a new user

All this involves is:

$ adduser USER
$ usermod -aG sudo USER

The first command creates the user named USER, prompts me for a new UNIX password plus a few details that you can skip through. The second command adds (appends) this user to the elite sudo group. I usually test this user by running login USER followed by the password I selected. I test the sudo capability by running a simple command like sudo apt update.

Sometimes I want to use sudo without entering the password every time. To do this, I open the sudoers file using the visudo command (similar to the vim editor), and append the following line at the end:

USER ALL=(ALL) NOPASSWD:ALL

Here I replace the word USER with my actual username, of course. This is useful when I want to run automated tasks (as this user) and minimize the amount of manual (aka human) intervention. I seldom set up this passwordless sudo capability, but it comes in handy from time to time.

2. Adding SSH keys

Next, I add my public SSH key to by editing the file ~/.ssh/authorized_keys as the new user and append the contents of a public key from my local machine. You can learn more about SSH at our guide.

3. Making sure that root can’t log in

I perform this step only after I’ve confirmed I can SSH into my VPS as the new USER. I also make sure this user can perform sudo actions otherwise, I might end up locking myself out of my brand-new VPS.

I edit the sshd_config file located at /etc/ssh/sshd_configto change thePermitRootLogin yes` line to:

…
PermitRootLogin no
…

This adds a bit of extra security, since the attacker now has to guess my username as well—no generic phrase like root would work. Also, if sudo privileges are protected by yet another user password, an attacker would have another hurdle before gaining total control over my VPS.

Another thing I to change inside this sshd_config file is the permission for using clear text passwords. Using SSH keys to login should be the norm since passwords are sent as clear text over the SSH channel and can compromise server security.

I uncomment the line #PasswordAuthentication ... and set its value to no as shown below:

…
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
#PermitEmptyPasswords no
...

4. Enabling a firewall

This is perhaps the most diverse topic, since firewalls differ from OS to OS. However, I mostly use Ubuntu, where ufw is easy to use and configure. I open a few important ports for SSH, HTTP, and HTTPS, and the rest stay shut:

$ sudo ufw allow ssh
$ sudo ufw allow http https
$ sudo ufw enable

I always make sure not to run ufw enable without opening the SSH port! That’s just another opportunity for me to lock myself out of my VPS.

I’m well aware that all these security measures could be improved upon—I could even automate most of them!


Installing the essentials

The essentials that I use every day for my environment are:

  • Docker
  • Git
  • LXC

The Docker installation is easy if you follow the official documentation or our getting started guide. It involves adding official the Docker repository to our list of trusted repositories and installing Docker from there. However, I like to create a new Docker network to use instead of the default network Docker provides.

This uses the same bridge driver as the default Docker network does, but is vastly easier to work with as documented here. The following command creates a new network my-network:

$ docker network create --driver bridge my-network

Containers on this network can talk to one another freely without the user having to expose any ports. I like to run untrusted containers in a different Docker network away from any sensitive data.

Using this bridge network significantly eases the process of deployment, and my Dockerfiles stay relatively free from EXPOSE commands. After this, I log in to my Docker Store. I use this sometimes to get a snapshot of a running container docker commit and save it in this registry for further use as a backup or for postmortem debugging if a container keeps crashing. Admittedly, this is a dirty way of doing this, and there are better alternatives. But if it ain’t broken…

While I’m at it, I also make a point of setting up my GitHub username. This is nothing special, but it does come handy at times.

A true container hypervisor

While Docker is great, I sometimes need a container that feels like an actual isolated operating system. For this, I use LX Containers.

LXC containers come with their own subnet, DNS and you can log in to any one of them and never realize that you are in a container, unless you know where to look. The storage comes from a nice OpenZFS backbone. This means automates backups using zfs send, super-fast and efficient compression and most importantly no chance of undetected data corruption.

You can get a glimpse of a simple LXC setup over here, and I hope you can get creative with it and get the most of out of your VPS.

What did I miss?

Hopefully, my setup inspired you to organize your VPS better. However, there’s always room for improvement. In case, you find that something in my setup can be improved upon, I would love to hear your constructive criticism. Feel free to email me at ranvir@numbersandreality.com!

]]>
https://www.ssdnodes.com/blog/server-setup-ranvir/feed/ 0
Hosting Multiple Websites With Containers And HAProxy https://www.ssdnodes.com/blog/linux-containers-lxc-haproxy/ https://www.ssdnodes.com/blog/linux-containers-lxc-haproxy/#respond Thu, 16 Aug 2018 07:00:11 +0000 https://blog.ssdnodes.com/blog/?p=2420

Hosting multiple websites on a single VPS via Docker is pretty cool, but others might find it too bloated or complex for their needs. Instead of Docker, we can use Linux Containers, also known as LXC, to do the same thing in a more streamlined, more Linux-y fashion.

Aim of this tutorial

In this tutorial, we will learn how to run multiple websites on a single VPS with a single public IP address. These websites will all run in their separate LX containers each with its own unique Fully Qualified Domain Name (FQDN). E.g, SUBDOMAIN1.DOMAIN.TLD and SUBDOMAIN2.DOMAIN.TLD, and so on.

We will achieve this by using one container to act as a load balancer, which will listen on all the requests coming on port 80 or 443 (more on these later) of your VPS. It will read the header information of the incoming request and if it is, say, SUBDOMAIN1.DOMAIN.TLD, it will forward the request to the corresponding backend container. If it is SUBDOMAIN2.DOMAIN.TLD, then the request goes to another container running a different website.

Lastly, we will setup TLS which to encrypt the entire communication between a client computer and your HAProxy container.

Prerequisites

  • A registered domain name. We will use a placeholder DOMAIN.TLD where you would use your own domain name instead.
  • An understanding of DNS records, especially A records and how to set those up.
  • Root access to a VPS with a static public IP.
  • Basic understanding of the Linux command line and how to use terminal-based editors like vim or nano. Use nano if you are new to this.

How are websites resolved?

a.k.a. Your DNS setup.

When you visit a website, say EXAMPLE.COM, your web browser makes a request to DNS servers, like those belonging to Google (8.8.8.8), OpenDNS (208.67.222.222), or CloudFlare (1.1.1.1). These DNS, or Domain Name Servers, check their records to see what public IP(s) it may point to. The IP is sent back to the browser. Then requests are made to this IP address which would then respond to them, typically, by sending over the contents of a webpage.

On the browser side, you typically expect these web pages to be served over port 80 (for HTTP) or port 443 (for HTTPS) of the server, so the browser sends requests to these particular ports, once it gets an IP address. How are we supposed to run multiple websites if only one or two ports are available to us?

Well, once we have a public IP with our VPS, we can set up multiple A records pointing different names to the same IP. So, if we want to launch websites SUBDOMAIN1.DOMAIN.TLD and SUBDOMAIN2.DOMAIN.TLD on a single server, both should point to the same IP address. Later on, we will set up a reverse proxy server which would send the traffic coming for SUBDOMAIN1.DOMAIN.TLD to one container and SUBDOMAIN2.DOMAIN.TLD to another container and so on.

But the important thing is that we will still be listening on port 80 and 443 on our web server, and no other ports, which is what we desire.

Initializing LXD and creating Linux containers

Let’s start with a clean slate Ubuntu 18.04 LTS server with no additional packages installed or any modifications made on it. Let’s run a customary update and upgrade on it, to make sure we have the latest packages made available to us.

$ sudo apt update
$ sudo apt upgrade

LXD init

LXD is the background process (a daemon), and Linux containers (LXC) is the containerization technology behind it. Now we can run lxd init, which will ask us several questions and set up the containerization environment for us. It would be better to use OpenZFS to store and manage our container related data.

$ sudo install zfsutils-linux
$ sudo lxd init

LXD will ask you a lot of technical questions, and we may not be able to cover all of them in depth. However, let’s stick to a brief description and get our LXC environment up and running.

  • When it comes to LXD clustering, we will use the default option, which is no. Just press <Enter>
  • New Storage Pool? Again, the default option yes.
  • Name of the storage pool? You can give it a reasonable name like lxc_pool, because default is not a meaningful name.
  • Storage backend? Let’s go with zfs, the default option.
  • Say yes to creating a new ZFS pool.
  • With block device, you have an option where you can create a new ZFS pool over an entire block device. If your VPS doesn’t have additional block storage attached to it, go with the default option of no.
    If you have selected no in the previous step, you would be asked to assign some space in the current file system which LXC will use. Default 15GB is a good starting point for it.
  • MAAS server connection is not required. Enter no.
  • Local Network Bridge is extremely important for what we are going to do. Answer that with a yes.
  • Let the bridge have the default name lxdbr0.
  • IPv4 addresses? Leave that to the default auto as well.
  • IPv6 addresses are strictly optional. For this tutorial, we are going to say none and not use the default value.
  • Say, no to making LXD available over the network.
  • Automatic update of Cached Images? yes of course!
  • You can print the summary of the entire configuration in the last prompt if you want to. Here’s the output of our configuration for reference.
config: {}
cluster: null
networks:
- config:
    ipv4.address: auto
    ipv6.address: auto
  description: ""
  managed: false
  name: lxdbr0
  type: ""
storage_pools:
- config:
    size: 15GB
  description: ""
  name: lxc_pool
  driver: zfs
profiles:
- config: {}
  description: ""
  devices:
    eth0:
      name: eth0
      nictype: bridged
      parent: lxdbr0
      type: nic
    root:
      path: /
      pool: lxc_pool
      type: disk
  name: default

If you are logged as a user which is not root, add that USER to your LXD group.

$ sudo usermod -aG lxd USER

Now, that we have LXD up and running, we can start creating our containers. LXC containers are different from Docker. You can treat Docker containers as simply a package that you’re installing, in a sense. LXC containers, on the other hand, are treated more like lightweight virtual machines each connected to each other with a private IP address and robust file systems and all the other things you typically associate with a VM.

Creating Linux containers

We will launch three containers by running:

$ lxc launch ubuntu:18.04 SUBDOMAIN1
$ lxc launch ubuntu:18.04 SUBDOMAIN2
$ lxc launch ubuntu:18.04 HAProxy

SUBDOMAIN1 is just a placeholder. You can name the container anything reasonable like blog or portfolio. You can see the state of each of them by using the command:

$ lxc list
+------------+---------+-----------------------+------+------------+-----------+
|    NAME    |  STATE  |         IPV4          | IPV6 |    TYPE    | SNAPSHOTS |
+------------+---------+-----------------------+------+------------+-----------+
| HAProxy    | RUNNING | 10.188.233.252 (eth0) |      | PERSISTENT | 0         |
+------------+---------+-----------------------+------+------------+-----------+
| SUBDOMAIN1 | RUNNING | 10.188.233.245 (eth0) |      | PERSISTENT | 0         |
+------------+---------+-----------------------+------+------------+-----------+
| SUBDOMAIN2 | RUNNING | 10.188.233.87 (eth0)  |      | PERSISTENT | 0         |
+------------+---------+-----------------------+------+------------+-----------+

The values above are just examples—your values might differ wildly from these.

IPTable Rules

Since all the incoming traffic (on port 80 and 443) should go through HAProxy first, let’s set some rules to enforce that. First, run the command:

$ ifconfig

Notice which network interface has the public IP address assigned to it. For example, one of the outputs of ifconfig will show your public IP under the inet entry. That particular interface’s name can be eth0 as shown below, or something else depending on your cloud provider. Use that name as your INTERFACE_NAME.

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet PUBLIC_IP_ADDRESS  netmask 255.255.240.0  broadcast
        inet6 fe80::387f:b5ff:fe8d:5960  prefixlen 64  scopeid 0x20<link>
        ether 3a:7f:b5:8d:59:60  txqueuelen 1000  (Ethernet)
        RX packets 1664438  bytes 1952362406 (1.9 GB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 853505  bytes 389343547 (389.3 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Forwarding traffic to the HAProxy container

Once that is done, note the IP address of your HAProxy container, as it was shown in lxc list. Let’s call it, HAPROXY_IP_ADDRESS, and also make a note of your VPS’s public IP address, let’s call it PUBLIC_IP_ADDRESS. Now, given these values, run:

$ sudo iptables -t nat -I PREROUTING -i INTERFACE_NAME -p TCP -d PUBLIC_IP_ADDRESS/32 --dport 80 -j DNAT --to-destination HAPROXY_IP_ADRESS:80

$ sudo iptables -t nat -I PREROUTING -i INTERFACE_NAME -p TCP -d PUBLIC_IP_ADDRESS/32 --dport 443 -j DNAT --to-destination HAPROXY_IP_ADRESS:443

We won’t go into the nuances of iptables right now—just understand that all the traffic to port 80 and 443 are routed to the HAProxy container. The above settings would reset themselves upon system reboot; we can use the package iptables-persistent to fix that:

$ sudo apt-get install iptables-persistent

For additional security, let’s secure the VPS by configuring the ufw firewall. It is essential that you allow ssh connections before you enable ufw. You might end up locking yourself out of your VPS, otherwise.

$ sudo ufw allow http
$ sudo ufw allow https
$ sudo ufw allow ssh
$ sudo ufw enable

Configuring HAProxy container

Login to your HAProxy container by executing the following command:

$ lxc exec HAProxy -- bash

Now the prompt would change, indicating that you are inside the container, as a root user root@HAProxy:~#. We will stay in this environment for the rest of this section. To go back to the main VPS environment, hit Ctrl+D or Cmd+D.

As the root user, you will want to run apt update and then install HAProxy server by running the following:

# apt install haproxy

This command installs and starts the HAProxy server, which is a reverse proxy server. Now, we would like to achieve the following:

Route traffic for SUBDOMAIN1.DOMAIN.TLD to SUBDOMAIN1 container.
Let the container know the client’s IP address so that it can keep track of different visitors to the SUBDOMAIN1.DOMAIN.TLD.
Ditto for SUBDOMAIN2.DOMAIN.TLD.
Optionally, add TLS certificates from Let’s Encrypt.

The configuration file for HAProxy is located at /etc/haproxy/haproxy.cfg. It will have two sections global and defaults. Let’s modify the global section first by adding two lines:

maxconn 2048
tune.ssl.default-dh-param 2048

And to the defaults sections add:

option  forwardfor
option  http-server-close

The result looks something like this:

global
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
        stats timeout 30s
        user haproxy
        group haproxy
        daemon
        maxconn 2048

        # Default SSL material locations
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        # Default ciphers to use on SSL-enabled listening sockets.
        # For more information, see ciphers(1SSL). This list is from:
        #  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
        ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
        ssl-default-bind-options no-sslv3
        tune.ssl.default-dh-param 2048

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        option  forwardfor
        option  http-server-close
        timeout connect 5000
        timeout client  50000
        timeout server  50000
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http

The maxconn parameter need not be 2048, but any value that you might deem fit as the maximum number of simultaneous connections. The forwardfor option is to retain the real source IP. The websites you have hosted can keep track of real-world visitors. Otherwise, it may appear that only the reverse proxy server has ever visited your websites SUBDOMAIN1.DOMAIN.TLD and SUBDOMAIN2.DOMAIN.TLD.

Now we need to add a frontend section at the bottom of the file, which will tell HAProxy how to filter the incoming requests. Then we will add a couple of backend sections telling haproxy where the filtered requests would go:

frontend http_frontend
    bind *:80

    acl web_host1 hdr(host) -i SUBDOMAIN1.DOMAIN.TLD
    acl web_host2 hdr(host) -i SUBDOMAIN2.DOMAIN.TLD

    use_backend subdomain1 if web_host1
    use_backend subdomain2 if web_host2

backend subdomain1
    balance leastconn
    http-request set-header X-Client-IP %[src]
    server SUBDOMAIN1 SUBDOMAIN1.lxd:80 check

backend subdomain2
    balance leastconn
    http-request set-header X-Client-IP %[src]
    server SUBDOMAIN2 SUBDOMAIN2.lxd:80 check

The above text is what you should append to the /etc/haproxy/haproxy.cfg file if you are interested in using just HTTP, without SSL. The frontend reads header information hdr(host) -i ... and distributes traffic accordingly.

The backend forwards the source IP set-header X-Client-IP %[SRC] and refers to the lxc containers using local domain names, like SUBDOMAIN1.lxd. This is a useful feature of LXD which we can use to our advantage. It is completely separate from the actual SUBDOMAIN1.DOMAIN.TLD that you would use to view your websites.

You can now check if the configuration file is okay or not by running:

# /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c

If everything checks out, restart HAProxy:

# service haproxy reload

You can now safely exit this container by running exit command.

Running multiple websites

Now you can login to the backend container named SUBDOMAIN1 and SUBDOMAIN2. We will install Nginx in one and Apache web server in other to see how they work.

$ lxc exec SUBDOMAIN1 -- bash
# apt install apache2
# exit
$ lxc exec SUBDOMAIN2 -- bash
# apt install nginx
# exit

Now if you visit SUBDOMAIN1.DOMAIN.TLD from your web browser, you will see that it is running Apache2 web server. Visiting SUBDOMAIN2.DOMAIN.TLD will show you an Nginx landing page instead!

You now have two different websites hosted on a single VPS. Login to their respective containers to install WordPress, Ghost, or another CMS, if you’re starting a blog. You can install anything you’d install on a barebones Linux VPS, such as self-hosted web apps, too.

Installing Let’s Encrypt certificates

We haven’t added SSL certificates, yet. If you are using Cloudflare as your DNS, you can enable SSL over there which would work just fine. It is free and easy to install. It will get your websites the green padlock symbol where the URL appears, and you won’t have to worry about certificate renewal.

If you want to use Let’s Encrypt for a free SSL certificate instead, you would have to jump through a couple of hoops. Let’s log back into the HAProxy container: lxc exec HAProxy -- bash.

Obtaining certs

First, disable the HAProxy service so we can get started with certificate installation. Add the Certbot PPA to your list of trusted repositories and then install Certbot, which will fetch certificates for us.

# service haproxy stop
# add-apt-repository ppa:certbot/certbot
# apt update
# apt install certbot

Obtain the certificates by running certbot certonly. This command will ask you several questions, including the domain names you want to have certified.

# certbot certonly
How would you like to authenticate with the ACME CA?
-------------------------------------------------------------------------------
1: Spin up a temporary web server (standalone)
2: Place files in webroot directory (webroot)
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):

Select 1. Then it would ask you for your email, enter it and Agree to terms and conditions. The command will also ask if you’re willing to share your email address with eff.org. You can opt out of it. Then, most importantly, you will be asked for your domain name(s). Enter your registered domain names. For example, we will enter SUBDOMAIN1.DOMAIN.TLD, SUBDOMAIN2.DOMAIN.TLD separated by a comma and a space.

Configuring HAProxy to serve SSL

If successful, it would tell you where the certs are stored. Typically the certificates are saved at /etc/letsencrypt/live/SUDOMAIN1.DOMAIN.TLD directory, which is named after the first FQDN you entered while obtaining the certificates.

We want to combine two files, the fullchain.pem and privkey.pem files, into a single file in a directory /etc/haproxy/certs.

$ mkdir -p /etc/haproxy/certs
$ cat /etc/letsencrypt/live/SUBDOMAIN1.DOMAIN.TLD/fullchain.pem /etc/letsencrypt/live/SUBDOMAIN1.DOMAIN.TLD/privkey.pem > /etc/haproxy/certs/SUBDOMAIN1.DOMAIN.TLD.pem

Next we must revisit our /etc/haproxy/haproxy.cfg file and add an SSL frontend to it, as well as modify the backend to redirect all non-SSL requests to SSL. We will add the SSL frontend first.

frontend www-https
    bind *:443 ssl crt /etc/haproxy/certs/SUBDOMAIN1.DOMAIN.TLD.pem
    reqadd X-Forwarded-Proto:\ https

    acl host_web1 hdr(host) -i SUBDOMAIN1.DOMAIN.TLD
    acl host_web2 hdr(host) -i SUBDOMAIN2.DOMAIN.TLD

    use_backend subdomain1 if host_web1
    use_backend subdomain2 if host_web2

Next, we will add the line redirect scheme https if !{ ssl_fc } in each of our backend section to redirect requests to SSL. Like so:

backend subdomain1
    balance leastconn
    http-request set-header X-Client-IP %[src]
    redirect scheme https if !{ ssl_fc }
    server SUBDOMAIN1 SUBDOMAIN1.lxd:80 check

The final result would look something like this:

frontend www-https
    bind *:443 ssl crt /etc/haproxy/certs/SUBDOMAIN1.DOMAIN.TLD.pem
    reqadd X-Forwarded-Proto:\ https

    acl host_web1 hdr(host) -i SUBDOMAIN1.DOMAIN.TLD
    acl host_web2 hdr(host) -i SUBDOMAIN2.DOMAIN.TLD

    use_backend subdomain1 if host_web1
    use_backend subdomain2 if host_web2

frontend http_frontend
    bind *:80

    acl web_host1 hdr(host) -i SUBDOMAIN1.DOMAIN.TLD
    acl web_host2 hdr(host) -i SUBDOMAIN2.DOMAIN.TLD

    use_backend subdomain1 if web_host1
    use_backend subdomain2 if web_host2

backend subdomain1
    balance leastconn
    http-request set-header X-Client-IP %[src]
    redirect scheme https if !{ ssl_fc }
    server SUBDOMAIN1 SUBDOMAIN1.lxd:80 check

backend subdomain2
    balance leastconn
    http-request set-header X-Client-IP %[src]
    redirect scheme https if !{ ssl_fc }
    server SUBDOMAIN2 SUBDOMAIN2.lxd:80 check

And you can now you can run service haproxy reload for the new configurations to take effect. Check if SSL is working or not by visiting your FQDNs from a web browser. You will see a secure symbol at the URL bar if everything as worked out fine.

Renewing certificates

Your certs expire every 90 days, and you would need to renew them accordingly. While this process can be automated, let’s look at a manual way to do this for the sake of simplicity.

  • Login to the HAProxy container: lxc exec HAProxy -- bash.
  • Stop the service: service haproxy stop.
  • Run: certbot renew.
  • Remove the older certificate from HAProxy configs rm /etc/haproxy/certs/SUBDOMAIN1.DOMAIN.TLD.pem.
  • Add the newer certs: cat
    /etc/letsencrypt/live/SUBDOMAIN1.DOMAIN.TLD/fullchain.pem
    /etc/letsencrypt/live/SUBDOMAIN1.DOMAIN.TLD/privkey.pem >
    /etc/haproxy/certs/SUBDOMAIN1.DOMAIN.TLD.pem
    .
  • Restart HAProxy: service haproxy start.

Conclusion

The overall setup covered here is quite complicated and can appear frustrating at times. If you feel that way, it’s okay! Knowing what you have done in every step of the way can teach you a lot about how these systems work and how you can optimally use them.

If you have any doubts, queries or corrections, feel free to drop a comment below.

]]>
https://www.ssdnodes.com/blog/linux-containers-lxc-haproxy/feed/ 0
What’s Next for SSD Nodes: KVM and Containers https://www.ssdnodes.com/blog/whats-next-for-ssd-nodes-kvm-and-containers/ https://www.ssdnodes.com/blog/whats-next-for-ssd-nodes-kvm-and-containers/#respond Wed, 26 Apr 2017 00:00:00 +0000 http://ssdnodes.billabailey.com/2017/04/26/whats-next-for-ssd-nodes-kvm-and-containers/

Here at SSD Nodes, we field a lot of feature and infrastructure requests from our customers. Of them all, the most prevalent might be: "When is KVM coming? When can I run Docker?"

It's a fair question, and one that's bugged us for a long time.

To take a step back, let's talk about OpenVZ, which is the current backbone of our operation. OpenVZ is a stable and powerful platform. Because it's using OS-level virtualization, the single shared kernel reduces memory and CPU usage across every VPS. It also allows us to scale specific VPS containers instantly and without downtime.

Of course, OpenVZ isn't perfect. It's limited to Linux distributions, and because it uses a shared kernel, you can't install a specific kernel version if you need to, or want to. OpenVZ 6 is based around a 2.6 kernel, which is not a supported configuration for Docker, which only officially supports kernels 3.10 or higher. If you run uname -a on your VPS right now, you'll see that our platform is running on the 2.6.32-042stab120.16 kernel.

KVM, on the other hand, is full hardware virtualization that allows you to install whichever kernel you'd like, or even a Windows VPS if you'd like.

A few months ago, we launched new data center locations in Seattle and NYC to give you the most choice and flexibility. That's what we're doing here, too.

So, in short: we're really close. The system is up and running, and we've thrown our engineering minds behind it. Essentially, we just need to ensure that every process is documented and then we'll be ready to launch.

Enter Virtuozzo

Virtuozzo is the enterprise-level version of OpenVZ—they're based around the same core components, but with significant improvements. Most notably:

  • A KVM-based hypervisor
  • Support for both KVM and containers
  • A 3.10+ Linux kernel
  • The ability to run Docker and other container technologies!
  • Storage quality of service (QoS) options to ensure that abusive customer don't negatively affect others
  • Reboot-less kernel upgrades

On top of that, Virtuozzo enables some other compelling features, such as automated snapshots and integrated backups/restores. There's also more flexible storage options, which allow us to create more unique packages or add-ons for those who require more disk space for their applications.

There's hardware changes, too

Right now, our physical servers are the lifeline for every VPS—if that server goes down, so do all the clients. That's not good.

Instead, Virtuozzo creates a distributed, highly available storage system, where the disks are separated from CPU/RAM servers. If a disk fails, it can be swapped out easily with no downtime. Even if an entire disk server fails, the load is dynamically spread across the other servers until we can get things back up and running again. If a CPU/RAM server goes down, those customers will get automatically rebooted on another. We pride ourselves on our availability, but this is yet another step in the right direction.

On top of that, Virtuozzo will make our hardware operations more efficient. Right now, we operate best when we our storage, CPU, and RAM are all equally utilized, but that's rarely the case. Our Montreal location runs out of RAM first, while in Dallas, storage gets eaten up, leaving underutilized RAM. By splitting CPU/RAM and storage into separate clusters, we can add only a CPU/RAM server when that's running low, or only a storage server when we need a few more TB to offer up.

These changes are going to make our operations more efficient, at higher availability, even as we offer more features to our customers. So, for us, this is an exciting next step in growing SSD Nodes to new heights.

Stay tuned for more details—we'll be sure you don't miss the official launch in just a short time.

]]>
https://www.ssdnodes.com/blog/whats-next-for-ssd-nodes-kvm-and-containers/feed/ 0