Setting up a Red Hat / Centos 7 yum repository with vsftpd, firewalld and SE Linux

Summary

This post describes how to set up your Red Hat or Centos 7 server to be a yum repository for both the local server and also serve other servers on the network via ftp using vsftpd. It uses the distro ISO as a source for the packages.

You need to be the root superuser to set this up.

These instructions create a local repo first and then using that insatll vsftpd and set up a remote repo available via ftp

Mount the ISO

Create a mount point and mount the iso image using a loopback mount.

# mkdir /mnt/iso
# mount -t iso9660 -o loop,ro rhel-server-7.1-x86_64-dvd.iso /mnt/iso
# df /mnt/iso
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/loop0 3798292 3798292 0 100% /mnt/iso

Create the repo directory and copy the packages to it.

mkdir -p /var/yum/repos.d/rhel7
cp -rpv /mnt/iso/Packages/ /var/yum/repos.d/rhel7

The cp command will take a while so the -v flag will show what it is doing.

Note: Instead of creating the repo in /var/yum/repos.d you could create it directly in the public ftp directory, see the steps for vstpd. However that assumes you can install vsftpd from somewhere already and you are happy to have the files directly in /var/ftp/pub. See the note in the section on configuring vsftpd.

Create the local repo with createrepo comamnd

# createrepo /var/yum/repos.d/rhel7
Spawning worker 0 with 1093 pkgs
Spawning worker 1 with 1093 pkgs
Spawning worker 2 with 1093 pkgs
Spawning worker 3 with 1092 pkgs
Workers Finished
Saving Primary metadata
Saving file lists metadata
Saving other metadata
Generating sqlite DBs
Sqlite DBs complete

Again this will take a few minutes as it analyses all the Packages.

If you don’t have the createrepo command installed then you can install it with yum if you currently have access to a remote repo on the internet or you can install the rpm from the Packages directory you just created

yum install createrepo

Or

cd /var/yum/repos.d/rhel7/Packages/
# ls createrepo*
createrepo-0.9.9-23.el7.noarch.rpm
# rpm -ivh createrepo-0.9.9-23.el7.noarch.rpm
Preparing... ################################# [100%]
Updating / installing...
1:createrepo-0.9.9-23.el7 ################################# [100%]

Set up your local repository

Now you have the repo created you can use it on the local system by setting up a repo conf file for it. Use your editor of choice (which is vi of course) to create repo

vi /etc/yum.repos.d/rhel7.repo

[rhel7]
name=Repo of installation iso packages
baseurl=file:///var/yum/repos.d/rhel7/
enabled=1
gpgcheck=0

Note the three /s in the file URI. gpgcheck is set to zero so that it will not look for signatures.

Confirm the repo is now available locally.

# yum clean all
Loaded plugins: langpacks, product-id, subscription-manager
Cleaning repos: rhel7
Cleaning up everything
# yum repolist enabled
Loaded plugins: langpacks, product-id, subscription-manager
rhel7 | 2.9 kB 00:00:00
rhel7/primary_db | 3.4 MB 00:00:00
repo id repo name status
rhel7 Repo of installation iso packages 4,371
repolist: 4,371

Install and configure vsftpd

Now the repo is available you can install it with yum. Then set the service to start automatically and allow it operate through your firewall if it is running.

# systemctl start vsftpd
# systemctl status vsftpd
vsftpd.service - Vsftpd ftp daemon
Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; enabled)
Active: active (running) since Sat 2015-09-05 14:14:58 BST; 14s ago
Process: 17389 ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf (code=exited, status=0/SUCCESS)
Main PID: 17390 (vsftpd)
CGroup: /system.slice/vsftpd.service
└─17390 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf

Sep 05 14:14:58 fitpc4.example.com systemd[1]: Starting Vsftpd ftp daemon...
Sep 05 14:14:58 fitpc4.example.com systemd[1]: Started Vsftpd ftp daemon.
systemctl enable vsftpd
ln -s '/usr/lib/systemd/system/vsftpd.service' '/etc/systemd/system/multi-user.target.wants/vsftpd.service'

We are going to use the default anonymous ftp configuration so the repo needs to be made available via /var/ftp/pub . You could have installed the packages into that directory directly but these instructions assume you have it set up elsewhere and want to be able to “link” it to /var/ftp/pub. You can’t use a symbolic link as vsftpd specifically disallows following links out from the chroot dir of the ftp user. So instead you can mount it locally.

Before all that though we have to test vsftpd is working and set up the firewall rules if applicable….

# systemctl status firewalld
firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled)
Active: active (running) since Sat 2015-09-05 11:10:16 BST; 3h 12min ago
Main PID: 12625 (firewalld)
CGroup: /system.slice/firewalld.service
└─12625 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid

If you are not using a firewall then you can skip the commands below that allow the ftp service

firewall-cmd --get-default-zone
public
# firewall-cmd --query-service=ftp
no
# firewall-cmd --query-service=ftp --permanent
no

If the service is not allowed then add it both in the runtime config and the permanent config.

# firewall-cmd --add-service=ftp
success
# firewall-cmd --add-service=ftp --permanent
success
# firewall-cmd --query-service=ftp
yes
# firewall-cmd --query-service=ftp --permanent
yes

You can now test vsftp by going to a remote server and using an ftp client to login anonymously. ( You can also test it locally ). If you don’t have an ftp client you can install a basic command line one using

yum install ftp

You should be able to log in and see the root directory. ( Which is chrooted to /var/ftp/ by default).

# ftp fitpc4.example.com
Connected to fitpc4.example.com (192.168.0.16).
220 (vsFTPd 3.0.2)
Name (fitpc4.example.com:root): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> pwd
257 "/"
ftp> ls
227 Entering Passive Mode (192,168,0,16,201,135).
150 Here comes the directory listing.
drwxr-xr-x 3 0 0 18 Sep 05 13:41 pub
226 Directory send OK.
ftp> quit
221 Goodbye.

Now we need to create a directory for the repository to be mounted and do a local bind mount of the local repo.

# mkdir /var/ftp/pub/rhel7
# mount --bind /var/yum/repos.d/rhel7/ /var/ftp/pub/rhel7/
# ls -l /var/ftp/pub/rhel7/
total 300
dr-xr-xr-x. 2 root root 229376 Feb 19 2015 Packages
drwxr-xr-x. 2 root root 4096 Sep 5 13:40 repodata

This only mounts the directory temporarily. So we need to umount it, add an entry to /etc/fstab and check it can automount

# umount /var/ftp/pub/rhel7/
# vi /etc/fstab

Append the following line

/var/yum/repos.d/rhel7/ /var/ftp/pub/rhel7/ none defaults,bind 0 0

Save the file and try the mount

# mount /var/ftp/pub/rhel7/
# ls -l /var/ftp/pub/rhel7/
total 300
dr-xr-xr-x. 2 root root 229376 Feb 19 2015 Packages
drwxr-xr-x. 2 root root 4096 Sep 5 13:40 repodata

Now at this point the only thing stopping ftp from accessing these files is if you have SE Linux running.

Check to see if it is in enforcing mode and what the contexts are for /var/ftp/pub and /var/yum/repos.d/rhel7/

# sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Max kernel policy version: 28
# ls -lZ /var/ftp/
drwxr-xr-x. root root system_u:object_r:public_content_t:s0 pub
# ls -lZ /var/ftp/pub/rhel7/
dr-xr-xr-x. root root unconfined_u:object_r:var_t:s0 Packages
drwxr-xr-x. root root unconfined_u:object_r:var_t:s0 repodata

Change the context type of the rhel7 dir and all its contents to be publicly readable:-

# chcon -R -t public_content_t /var/ftp/pub/rhel7/
# ls -lZ /var/ftp/pub/rhel7/
dr-xr-xr-x. root root unconfined_u:object_r:public_content_t:s0 Packages
drwxr-xr-x. root root unconfined_u:object_r:public_content_t:s0 repodata

Now when I connect with anonymous ftp I can see the contents of the directories.

ftp> pwd
257 "/"
ftp> ls
227 Entering Passive Mode (192,168,0,16,201,135).
150 Here comes the directory listing.
drwxr-xr-x 3 0 0 18 Sep 05 13:41 pub
226 Directory send OK.
ftp> cd pub
250 Directory successfully changed.
ftp> ls
227 Entering Passive Mode (192,168,0,16,131,200).
150 Here comes the directory listing.
drwxr-xr-x 4 0 0 36 Sep 05 12:40 rhel7
226 Directory send OK.
ftp> ls rhel7
227 Entering Passive Mode (192,168,0,16,134,133).
150 Here comes the directory listing.
dr-xr-xr-x 2 0 0 229376 Feb 19 2015 Packages
drwxr-xr-x 2 0 0 4096 Sep 05 12:40 repodata
226 Directory send OK.
ftp> quit
221 Goodbye.

The final step is to now log on to the remote client that wants to use this repo and set up the repos conf file.

# vi /etc/yum.repos.d/remote.repo

[remote]
name=Remote Repo from fitpc4
baseurl=ftp://fitpc4.example.com/pub/rhel7
enabled=1
gpg-check=0

Now you can install from this remote depot e.g.

# yum clean all
Loaded plugins: langpacks, product-id
Cleaning repos: remote
Cleaning up everything
# yum repolist
Loaded plugins: langpacks, product-id
remote | 2.9 kB 00:00:00
remote/primary_db | 3.4 MB 00:00:01
repo id repo name status
remote Remote Repo from fitpc4 4,371
repolist: 4,371
# yum install ftp
Loaded plugins: langpacks, product-id
Resolving Dependencies
--> Running transaction check
---> Package ftp.x86_64 0:0.17-66.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

=================================================================================================================================
Package Arch Version Repository Size
=================================================================================================================================
Installing:
ftp x86_64 0.17-66.el7 remote 61 k

Transaction Summary
=================================================================================================================================
Install 1 Package

Total download size: 61 k
Installed size: 96 k
Is this ok [y/d/N]: y
Downloading packages:
ftp-0.17-66.el7.x86_64.rpm | 61 kB 00:00:01
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : ftp-0.17-66.el7.x86_64 1/1
Verifying : ftp-0.17-66.el7.x86_64 1/1

Installed:
ftp.x86_64 0:0.17-66.el7

Complete!

Troubleshooting

If you have problems check the SE linux logs in /var/log/audit.
If you get really stuck try temporarily disabling the firewall and see if that helps. Similarly try temporarily put the SE Linux into permissive mode ( that needs a reboot).
See references below for how to do those things.
These measures should only be temporary to let you diagnose where the issue is.

References

I used lots of sources whilst I was trying to set this up. None of them quite covered all the steps (hence writing this blog to put it all in one place for RHEL 7) but the ones below helped a lot.

FTP & SE Linux
SELinux and vsftpd on CENTOS
Creating a repo using vsftpd
Mount –bind and fstab
Disable firewall
SELinux Permissive Mode