Skip to main content

Raymii.org Raymii.org Logo

Quis custodiet ipsos custodes?
Home | About | All pages | Cluster Status | RSS Feed

Ansible - Add an apt-repository on Debian and Ubuntu

Published: 15-05-2016 | Last update: 14-12-2018 | Author: Remy van Elst | Text only version of this article


❗ This post is over five years old. It may no longer be up to date. Opinions may have changed.


This is a guide that shows you how to add an apt repository to Debian and Ubuntu using Ansible. It includes both the old way, when the apt modules only worked on Ubuntu, and the new way, now that the apt-modules also support Debian, plus some other tricks.

Recently I removed all Google Ads from this site due to their invasive tracking, as well as Google Analytics. Please, if you found this content useful, consider a small donation using any of the options below:

I'm developing an open source monitoring app called Leaf Node Monitoring, for windows, linux & android. Go check it out!

Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.

You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $200 credit for 60 days. Spend $25 after your credit expires and I'll get $25!

  • 14-12-2018: updated ansible syntax to 2.5
  • 15-05-2016: initial article

Introduction

Ansible allows you to add apt repositories and apt repository signing keys easily using the two modules apt_repository and apt_key. You can use this when you need to install packages from an external location, for example, nginx or goaccess. Both of these packages are in the repositories, but not the latest version.

Using Ansible you can add the repository and the signing key, and then install the package from the new repo. This guide will show you a few ways to do that in playbooks.

The new way

The easy way is to first add the repository key, then add the repository and finally install the package. Here's an example for nginx:

# always try to use HTTPS. I'm not sure why the nginx folks don't provide it.
- name: add nginx apt-key
  apt_key: 
    url: http://nginx.org/keys/nginx_signing.key 
    state: present 

- name: add nginx apt repository
  apt_repository: 
    repo: 'deb http://nginx.org/packages/mainline/ubuntu/ xenial nginx' 
    state: present 
    filename: nginx 
    update_cache: yes

- name: install nginx
  apt: 
    name: nginx
    state: present
    update_cache: yes

This is a three line playbook which will download and install the repository key, add the repository to a seperate file in /etc/apt/sources.list.d/ and install the package while also doing an apt-get update to refresh the apt cache with the new repository.

This is the recommended way to add a repo and install packages from there. Read on to find out the workarounds in ye olden days.

The old way

In the past the apt_key module and behaved wonky on Debian installations, but not on Ubuntu. The apt_key module also did not support downloading keys from external locations and was tailored more to PPA's, which are nonexistent on Debian. Here's the same NGINX example, using the older way, which still works by the way.

- name: 'add nginx repository'
  template: 
    src: nginx.list.j2
    dest: /etc/apt/sources.list.d/nginx.list

- name: make sure folder /var/keys exists
  file: 
    path: /var/keys
    state: directory 
    owner: root

- name: 'get nginx package signing key'
  get_url: 
    url: http://nginx.org/keys/nginx_signing.key
    dest: /var/keys/nginx_signing.key
  register: result

- name: add nginx apt-key
  command: apt-key add '/var/keys/nginx_signing.key'
  when: result.changed

- name: install nginx
  apt:
    name: nginx 
    state: latest
    update_cache: yes

The nginx repository template contains the following:

# {{ ansible_managed }}
deb http://nginx.org/packages/mainline/{{ ansible_lsb.id|lower }}
/ {{ ansible_lsb.codename|lower }} nginx

deb-src http://nginx.org/packages/mainline/{{ ansible_lsb.id|lower }}
/ {{ ansible_lsb.codename|lower }} nginx

This is quite a nice trick, because it works on both Debian and Ubuntu, all versions. On the latest Ubuntu 16.04 the resulting repository line is this:

deb http://nginx.org/packages/mainline/ubuntu/ xenial nginx

But on an onder Debian installation, the result is this:

deb http://nginx.org/packages/mainline/debian/ wheezy nginx

You do need to make sure the upstream repository also follows this structure. In the nginx case, it does.

First a directory is created for the keyfile. The apt-key is downloaded manually to there, the result is registered. If the key already exists or is the same, we don't do anything. If the key isn't there or has changed, we execute the apt- key add command manually to add the repository signing key. If that's all done, we update the apt-cache and install nginx.

That's quite a bit more steps and ways to break stuff, plus, less idempotent due to the manual command. My playbook was so old, it still used the action: apt instead of just apt:.

This is not the recommended way, but it still works just fine. If you add repositories this way, no problem, but you might want to consider rewriting the playbooks to the newer way.

More documentation

The official documentation for the two modules can be found on the Ansible docs site: apt_repository and apt_key.

You can also check out my other Ansible articles.

Tags: ansible , apt , deb , nginx , packages , python , repo , tutorials