https://intoli.com/blog/installing-google-chrome-on-centos/
The Easy Way
Universal Installation Script for RHEL/CentOS 6.X/7.X
All you need to do is run our installer script and you should be good to go.
curl https://intoli.com/install-google-chrome.sh | bash
This will automatically configure and enable the official Google repository, import Google’s signing key, and install the latest google-chrome-stable
executable in your path. If you’re on a RHEL 6.X flavor the it will also automatically find and install all of the unmet dependencies that would normally make the installation fail. You can rerun the script whenever you want to grab the latest version of Google Chrome and, if you’re using RHEL 7.X, then you can update the package using yum
as you would with any other package.
RHEL/CentOS 7.X
Alternatively, you can add the repository manually if you’re using a 7.X version. If you’re using Amazon Linux AMI then you’re definitely on a 6.X version and need to use the installation script. Otherwise, you can run
cat /etc/redhat-release
and check the output for the version number to confirm that you’re using 7.X. For example, if you’re using RHEL 7.0 then you would expect to see something like:
Red Hat Enterprise Linux Server release 7.0 (Maipo)
You can use the official Google repository if you see a 7.X version there. To add it to your system, simply create a file called /etc/yum.repos.d/google-chrome.repo
with the following contents.
[google-chrome]
name=google-chrome
baseurl=http://dl.google.com/linux/chrome/rpm/stable/$basearch
enabled=1
gpgcheck=1
gpgkey=https://dl-ssl.google.com/linux/linux_signing_key.pub
Then you just need to run
sudo yum install google-chrome-stable
to install the Chrome package. This will add the google-chrome-stable
script in /usr/bin/
. Note that this is the same thing that the installation script does on 7.X flavors, so it’s safe to use the script regardless of which version you’re on.
The Hard Way
If you just want to install Google Chrome on a RHEL variant then I highly recommend using our installation script in the previous section. That said, I’ll walk through the process of doing it manually because some of our more technical readers might find it interesting. The basic idea is to use the 7.X Google Chrome RPM as a starting point and then to install the dependencies and extras that we need in order for it to work on 6.X versions. This process is exactly the same as the one employed by the installation script above.
Getting the RPM
First, we’ll grab the official RPM file for the 7.X variants. It won’t work out of the box on 6.X versions, but it gives us a good starting point for making changes. We can download the file by creating the same /etc/yum.repos.d/google-chrome.repo
file that we would use with the 7.X versions
[google-chrome]
name=google-chrome
baseurl=http://dl.google.com/linux/chrome/rpm/stable/$basearch
enabled=1
gpgcheck=1
gpgkey=https://dl-ssl.google.com/linux/linux_signing_key.pub
and then running:
# install the yum utilities
sudo yum install yum-utils
# download the google-chrome-stable package
yumdownloader google-chrome-stable
The second command should download the RPM file to the current working directory. The current version has a file name of google-chrome-stable-63.0.3239.108-1.x86_64.rpm
, but this will change as new versions get released.
Installing the (Broken) Package
Let’s start by installing as many of the dependencies of google-chrome-stable
as we can. This can be done by using repoquery
, another tool provided by yum-utils
, to resolve the dependency packages and then passing these as arguments to yum
using xargs
.
repoquery --requires --resolve google-chrome-stable | xargs sudo yum -y install
After these finish installing, we can try to install the downloaded RPM.
sudo rpm -i google-chrome-stable-63.0.3239.108-1.x86_64.rpm
This will output a list of dependencies that aren’t available on the system.
error: Failed dependencies:
libXss.so.1()(64bit) is needed by google-chrome-stable-63.0.3239.108-1.x86_64
libatk-1.0.so.0()(64bit) is needed by google-chrome-stable-63.0.3239.108-1.x86_64
libgconf-2.so.4()(64bit) is needed by google-chrome-stable-63.0.3239.108-1.x86_64
libgdk-3.so.0()(64bit) is needed by google-chrome-stable-63.0.3239.108-1.x86_64
libgdk_pixbuf-2.0.so.0()(64bit) is needed by google-chrome-stable-63.0.3239.108-1.x86_64
libgtk-3.so.0()(64bit) is needed by google-chrome-stable-63.0.3239.108-1.x86_64
xdg-utils is needed by google-chrome-stable-63.0.3239.108-1.x86_64
Let’s go ahead and install the package anyway, this time skipping the missing dependencies with the --nodeps
option.
sudo rpm -i --nodeps google-chrome-stable-63.0.3239.108-1.x86_64.rpm
You’ll likely see an error like
Error: Could not find xdg-icon-resource
warning: %post(google-chrome-stable-63.0.3239.108-1.x86_64) scriptlet failed, exit status 1
because the RPM’s installation script includes the following code for installing the icons using xdg-icon-resource
.
# Add icons to the system icons
XDG_ICON_RESOURCE="`which xdg-icon-resource 2> /dev/null || true`"
if [ ! -x "$XDG_ICON_RESOURCE" ]; then
echo "Error: Could not find xdg-icon-resource" >&2
exit 1
fi
for icon in "/opt/google/chrome/product_logo_"*.png; do
size="${icon##*/product_logo_}"
"$XDG_ICON_RESOURCE" install --size "${size%%.png}" "$icon" "google-chrome"
done
This isn’t anything to worry about, the installation most likely still worked even if you saw this error. If you run google-chrome-stable
at this point, however, you’ll see an error like this.
/usr/bin/google-chrome-stable: error while loading shared libraries: libgconf-2.so.4: cannot open shared object file: No such file or directory
This one is more serious. Note that this libgconf-2.so.4
was one of the missing dependencies that was listed before we forced the installation of the RPM. It turns out that we actually do need those dependencies after all!
Providing the Missing Dependencies
Running the Chrome executable told us one missing library, but we can use ldd
to get a more complete picture of the missing shared libraries that google-chrome-stable
links to.
ldd /opt/google/chrome/chrome | grep "not found"
This command will output the list of missing libraries, all of which are ones that we removed as requirements.
libgconf-2.so.4 => not found
libXss.so.1 => not found
libatk-1.0.so.0 => not found
libgtk-3.so.0 => not found
libgdk-3.so.0 => not found
libgdk_pixbuf-2.0.so.0 => not found
We could try to build these libraries ourselves, or even to create new packages for them, but this would end up being an immense amount of work because each of these will have their own sets of dependencies. A much easier solution is to grab these files from another GNU/Linux system where the same version of Google Chrome is installed. This is a bit of a hack, but it’s the easiest way to get things working quickly.
There are two questions to answer here: where to get the libraries from and where to put them. Let’s start with where to put them because there’s an easy answer. One obvious choice would be /usr/lib64/
, but we would eventually end up with some library files that are in conflict with existing system libraries. Plus it’s kind of gross to dump files that aren’t controlled by the package manager into those system directories. What are we, Mac users?
If we look inside of the /usr/bin/google-chrome-stable
script, we can see that it actually prepends a few directories of its own to LD_LIBRARY_PATH
before it launches Chrome.
# Always use our versions of ffmpeg libs.
# This also makes RPMs find the compatibly-named library symlinks.
if [[ -n "$LD_LIBRARY_PATH" ]]; then
LD_LIBRARY_PATH="$HERE:$HERE/lib:$LD_LIBRARY_PATH"
else
LD_LIBRARY_PATH="$HERE:$HERE/lib"
fi
export LD_LIBRARY_PATH
With the standard Chrome installation location, the extra library paths are /opt/google/chrome/
and /opt/google/chrome/lib/
. These directories will be searched for dependencies before any of the system directories and they’re nicely colocated with the Chrome installation. The /opt/google/chrome/lib/
directory is actually non-existent in the package, but it’s a convenient location to place all of our library files.
Now we’re ready for the harder question: where do we get the libraries from? Well, given that the Chrome RPM can be installed successfully on CentOS 7, that seems like a good place to look. The same repoquery
utility that we used earlier makes it possible to query remote repositories to find the RPMs that provide certain files. Let’s take the missing libgconf-2.so.4
for example.
# Search the CentOS 7 repository for the missing file.
repoquery --repofrompath=centos7,http://mirror.centos.org/centos/7/os/`arch` \
--repoid=centos7 \ # Only consider this specific repository.
--qf="%{location}" \ # Output the URL of the RPM file.
--whatprovides libgconf-2.so.4 # Find the package that provides this library.
This command will output
http://mirror.centos.org/centos/7/os/x86_64/Packages/GConf2-3.2.6-8.el7.i686.rpm
which is so close, but not quite right. You can see from the /x86_64/
in the URL that the architecture for this repository for 64 bit, but the .i686.rpm
indicates that this is the 32 bit package. We’ll need to manually change the suffix to .x86_64.rpm
to specify the correct architecture for our CentOS 6 system (assuming that you’re using a 64 bit version).
After modifying the URL, we can download the RPM and extract it by running the following.
# Change to a temporary directory.
mkdir -p /tmp/working-directory/
cd /tmp/working-directory/
# Download the RPM.
wget http://mirror.centos.org/centos/7/os/x86_64/Packages/GConf2-3.2.6-8.el7.x86_64.rpm
# Extract it.
rpm2cpio GConf2-3.2.6-8.el7.x86_64.rpm | cpio -idmv
This will dump all of the files included in the package into the current working directory. We only really care about a couple of those files and we can find them by running
find . | grep libgconf-2.so.4
which will output the matching libraries.
./usr/lib64/libgconf-2.so.4.1.5
./usr/lib64/libgconf-2.so.4
The libgconf-2.so.4
file is the one that ldd
was looking for, but it’s actually a symlink to libgconf-2.so.4.1.5
so we need both. Let’s copy these to our /opt/google/chrome/lib/
directory and try ldd
again.
# Make the directory because it didn't exist already.
sudo mkdir /opt/google/chrome/lib/
# Copy the files over.
sudo cp ./usr/lib64/libgconf-2.so.4 /opt/google/chrome/lib/
sudo cp ./usr/lib64/libgconf-2.so.4.1.5 /opt/google/chrome/lib/
# Add this directory to LD_LIBRARY_PATH and run `ldd`.
export LD_LIBRARY_PATH=/opt/google/chrome/lib/:$LD_LIBRARY_PATH
ldd /opt/google/chrome/chrome | grep "not found"
Note that we’re explicitly adding the directory to LD_LIBRARY_PATH
so that ldd
knows about it. This happens automatically when we run google-chrome-stable
, but we need to make sure we add it ourselves if we want to use these libraries outside of that context. Anyway, ldd
will now output a revised list of missing depdendencies.
libXss.so.1 => not found
libatk-1.0.so.0 => not found
libgtk-3.so.0 => not found
libgdk-3.so.0 => not found
libgdk_pixbuf-2.0.so.0 => not found
libdbus-glib-1.so.2 => not found
Notice anything different? That’s right, no more missing libgconf-2.so.4
dependency for us. We evidently traded it for a brand new libdbus-glib-1.so.2
dependency instead.
It essentially becomes a game of whack-a-mole at this point. You fix one dependency and a new secondary dependency pops up. As you might have guessed, it’s not much fun to do this by hand. Definitely more of a script type of job. Hmmm… somebody should really make one of those.
The basic gist of what the installation script does is to run ldd
, loop through the missing dependencies, find the CentOS 7 packages that provide them, download and extract them, copy over the library files, and then repeat until everything is right in the world. It’s probably easiest to just see the code.
# Loop through and install missing dependencies.
while true
do
finished=true
# Loop through each of the missing libraries for this round.
while read -r line
do
if [[ $line == *"/"* ]]; then
# Extract the filename when a path is present (e.g. /lib64/).
file=`echo $line | sed 's>.*/\([^/:]*\):.*>\1>'`
else
# Extract the filename for missing libraries without a path.
file=`echo $line | awk '{print $1;}'`
fi
# We'll require an empty round before completing.
finished=false
echo "Finding dependency for ${file}"
# Find the URL for the Centos 7 RPM containing this library.
url=$(repoquery --repofrompath=centos,http://mirror.centos.org/centos/7/os/`arch` \
--repoid=centos -q --qf="%{location}" --whatprovides $file | \
sed s/x86_64.rpm$/`arch`.rpm/ | \
sed s/i686.rpm$/`arch`.rpm/g
)
# Download the RPM.
wget "${url}" -O ${file}.rpm
# Extract it and remove it.
rpm2cpio ${file}.rpm | cpio -idmv
rm ${file}.rpm
# Copy it over to our library directory and clean up.
find . | grep /${file} | xargs -n1 -I{} sudo cp {} /opt/google/chrome/lib/
rm -rf *
done < <(ldd /opt/google/chrome/chrome 2>&1 | grep -e "no version information" -e "not found")
# Break once no new files have been copied in a loop.
if [ "$finished" = true ]; then
break
fi
done
If you copy and paste that big hunk of code into your terminal, it should download and install all of the dependencies that you need. Once the dust settles, there will be about 30 library files that have been added to /opt/google/chrome/lib/
. If my calculations are correct… everything should just work at this point.
To verify this, we can run Google Chrome in headless mode and take a screenshot
google-chrome-stable --headless --disable-gpu --screenshot \
https://intoli.com/blog/installing-google-chrome-on-centos/
which will produce a beautiful screenshot.png
file.