Skip to content

CentOS as guest in Proxmox

Template to install quickly a functional Debian VM inside Proxmox VE.

Proxmox Settings

First step you must fix MAC ADDRESS on Proxmox-GUI.

  • Select your VM's
  • Select Hardware tab and go to Network Device
  • Clic to edit and add your MAC ADDRESS

Debian installation


  • LANG = English UTF8
  • Country = Belgium
  • Keyboard = Belgian
  • Timezone = Europe/Brussels



In case or you have only one IP you can use masquerading

If you choose to work with ip failover you must look on your DNS provider to obtain an valid IP address and domain name because every VM must have his own ip and mac address just like a real server.

In my case I work with OVH & SoYouStart solutions.

So, in our set up every VM's must have his own IP failover.

Example if you have IP

The settings that should be applied

  • IP to
  • Netmask to
  • Gateway to
  • Nameserver to

If these settings aren't set up you can't access to internet.

Disk and boot loader

I have one disk it is /dev/sda with size of 30Gio.

My partitions schema

  • /dev/sda1 size = 512MB formated in ext2 mounted under /boot.
  • /dev/sda2 size = all space left. You must configure LVM and add sda2 in a VolumeGroup. I have called my VG systemdeb.
  • /dev/systemdeb/swap = 1Go formated in swap.
  • /dev/systemdeb/root = 10Go formated in XFS.
  • /dev/systemdeb/var = 15Go formated in XFS.
  • /dev/systemdeb/tmp = 3Go formated in XFS.

Set up CentOS

System update + root pass change

At this time we can't login via SSH so go by Proxmox-GUI shell and log in root.

We change root password and we add epel repository with Development tools to have all tools to compile.

passwd root
passwd $USER
yum install -y epel-release && yum update && yum -y groupinstall "Development tools"
yum install -y qemu-guest-agent iptraf-ng

For root & user password it is highly recommend to use an password generator like builtin in buttercup/keepass software with 24 characters. (char + special char + digits + underline/score no blank space)


Reboot the VM to apply support of qemu-guest-agent.

Software base

To work on my server I use every time same tools to mana.

yum install -y net-tools nano nc ccze  htop git vim zsh ncdu  lftp curl wget rsync mlocate  multitail lnav

Shell set up and improvement

To improve the work flow with the the shell we use ZSH with OhMyZsh framework. It is easy to use, configure and deploy.

Get OhMyZsh

We donwload the script to install the framework

sh -c "$(wget -O -)"

ZSHRC improvement


We modify our .zshrc but take for export ZSH value you must adapt it to your own installation. Adapt the path to the VM user.

Edit our ~/.zshrc as beneath

# Path to your oh-my-zsh installation.
export ZSH="/home/$USERNAME/.oh-my-zsh" #adapt to your installation

# looking in ~/.oh-my-zsh/themes/

# Uncomment the following line to use case-sensitive completion.

# Uncomment the following line to use hyphen-insensitive completion. Case
# sensitive completion must be off. _ and - will be interchangeable.

# Uncomment the following line to disable bi-weekly auto-update checks.

# Uncomment the following line to change how often to auto-update (in days).

# Uncomment the following line to disable colors in ls.

# Uncomment the following line to disable auto-setting terminal title.

# Uncomment the following line to enable command auto-correction.

# Uncomment the following line to display red dots whilst waiting for completion.

# Uncomment the following line if you want to change the command execution time
# stamp shown in the history command output.
# The optional three formats: "mm/dd/yyyy"|""|"yyyy-mm-dd"

# Would you like to use another custom folder than $ZSH/custom?
# ZSH_CUSTOM=/path/to/new-custom-folder

# Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*)
# Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.

source $ZSH/

# User configuration
export MANPATH="/usr/local/man:$MANPATH"

# You may need to manually set your language environment
export LANG=en_US.UTF-8

# Preferred editor for local and remote sessions
if [[ -n $SSH_CONNECTION ]]; then
  export EDITOR='vim'
  export EDITOR='nano'

# Compilation flags
export ARCHFLAGS="-arch x86_64"

# ssh
export SSH_KEY_PATH="~/.ssh/rsa_id"

# Personnal alias #

# System
alias sysctlres="sudo systemctl restart"
alias sysctlrel="sudo systemctl reload"
alias sysctlstart="sudo systemctl start"
alias sysctlstop="sudo systemctl stop"
alias sysctlstat="sudo systemctl status"
alias sysctlist="sudo systemctl list-units -t service"
alias sysctlupd="sudo yum update"
alias sysctlupgr="sudo yum upgrade"

# Tools
alias ncdu="ncdu --color dark"
alias netstat="netstat -plntu"
alias netstatfull="netstat -nlapute"

VIMRC improvement

In server environment I use vim to edit my conf files so go to edit our ~/.vimrc as beneath

syntax on
filetype indent on

set background=dark
set t_Co=256
set smartindent
set number
set showcmd
set showmode
set nobackup
set nowritebackup
set hlsearch
set autoindent
set ignorecase
set laststatus=2

" Remember last position of the cursor
augroup resCur
  autocmd BufReadPost * call setpos(".", getpos("'\""))
augroup END

  " Git Branch Info
function! GitBranch()
  return system("git rev-parse --abbrev-ref HEAD 2>/dev/null | tr -d '\n'")

" Line Status
  function! StatuslineGit()
    let l:branchname = GitBranch()
      return strlen(l:branchname) > 0?'  '.l:branchname.' ':''

      set statusline=
      set statusline+=%#PmenuSel#
      set statusline+=%{StatuslineGit()}
      set statusline+=%#LineNr#
      set statusline+=\ %f
      set statusline+=%m\
      set statusline+=%=
      set statusline+=%#CursorColumn#
      set statusline+=\ %y
      set statusline+=\ %{&fileencoding?&fileencoding:&encoding}
      set statusline+=\[%{&fileformat}\]
      set statusline+=\ %p%%
      set statusline+=\ %l:%c
      set statusline+=\
      set statusline=%<%F%h%m%r%h%w%y\ %{&ff}\ %{strftime(\"%c\",getftime(expand(\"%:p\")))}%=\lin:%l\,%L\ col:%c%V\ pos:%o\ ascii:%b\ %P

User & group management

In our case we have deploy the CentOS ISO on our VM. During his installation process centos have create two users, the root and your $USER.

By default your user is member of wheel group. In CentOS it is the base group to have sudo access.

If you't member of this group you can add your user to wheel by typing usermod -aG wheel $USER.

In case where you want to create a new user and add this user to a group called "myteam" with sudo access and zsh as shell.

useradd $USER -mG wheel,myteam -s /bin/zsh -c "Your Name"
passwd $USER

Change the behavior of SWAP

By default linux starts using your swap memory as soon as you exceed 40% of your RAM usage.

This is the default behavior and we will change it to avoid unnecessary performance losses.

Edit your /etc/sysctl.conf

and add vm.swappiness = 10 at the end of the file.

After the reboot your system start to use the swap when is reach 90% of the total memory.

Set up SSH

First, save your actual sshd_config to avoid to brok your service.

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak

When it's saved edit sshd_config as beneath

# What ports, IPs and protocols we listen for
Port 65022
# Use these options to restrict which interfaces/protocols sshd will bind to
ListenAddress ::
Protocol 2
# HostKeys for protocol version 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
#Privilege Separation is turned on for security
UsePrivilegeSeparation yes

# Lifetime and size of ephemeral version 1 server key

# Logging
SyslogFacility AUTH
LogLevel INFO

# Authentication:
LoginGraceTime 120
PermitRootLogin prohibit-password
StrictModes yes

#AuthorizedKeysFile %h/.ssh/authorized_keys

# Don't read the user's ~/.rhosts and ~/.shosts files
IgnoreRhosts yes
# For this to work you will also need host keys in /etc/ssh_known_hosts
# similar for protocol version 2
HostbasedAuthentication no
# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
#IgnoreUserKnownHosts yes

# To enable empty passwords, change to yes (NOT RECOMMENDED)
PermitEmptyPasswords no

# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no

# Change to no to disable tunnelled clear text passwords
PasswordAuthentication yes

# Kerberos options
#KerberosAuthentication no
#KerberosGetAFSToken no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes

# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes

X11Forwarding no
#X11DisplayOffset 10
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
#UseLogin no

#MaxStartups 10:30:60
#Banner /etc/

# Allow client to pass locale environment variables

Subsystem sftp /usr/lib/openssh/sftp-server

# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication.  Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes

Restart sshd.service and verify if everything works fine

systemctl restart sshd.service && systemctl status sshd.service
netstat -nlapute #normally will display an list open ports on your machine



Security-Enhanced Linux (SELinux) is a mandatory access control (MAC) security mechanism implemented in the kernel. SELinux was first introduced in CentOS 4 and significantly enhanced in later CentOS releases. These enhancements mean that content varies as to how to approach SELinux over time to solve problems.

Some of the problems

In order to better understand why SELinux is important and what it can do for you, it is easiest to look at some examples. Without SELinux enabled, only traditional discretionary access control (DAC) methods such as file permissions or access control lists (ACLs) are used to control the file access of users. Users and programs alike are allowed to grant insecure file permissions to others or, conversely, to gain access to parts of the system that should not otherwise be necessary for normal operation. For example :

  • Administrators have no way to control users: A user could set world readable permissions on sensitive files such as ssh keys and the directory containing such keys, customarily: ~/.ssh/
  • Processes can change security properties: A user's mail files should be readable only by that user, but the mail client software has the ability to change them to be world readable.
  • Processes inherit user's rights: Firefox, if compromised by a trojaned version, could read a user's private ssh keys even though it has no reason to do so.

Essentially under the traditional DAC model, there are two privilege levels, root and user, and no easy way to enforce a model of least-privilege. Many processes that are launched by root later drop their rights to run as a restricted user and some processes may be run in a chroot jail but all of these security methods are discretionary.

SELinux status

We want to know if SELinux is running. We have two commands line to know the status.

# With similar output when activated
SELinux status:                 enabled
SELinuxfs mount:                /selinux
Current mode:                   enforcing
Mode from config file:          enforcing
Policy version:                 21
Policy from config file:        targeted

# or this output when is desactivated
SELinux status:                 disabled

Or with getenforce


Enforcing # With this output when activated

Disabled # Or this output when is desactivated

Disable SELinux

In function of what I need to do I use SELinux but for my template installation I prefer to disable it.

To disable SELinux you must edit /etc/sysconfig/selinux like beneath.

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
# SELINUXTYPE= can take one of three two values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected.
#     mls - Multi Level Security protection.

The end

Now you have a base VM to works and install every services what you need. You can continue by improvement the security configuration of SSH (rsa key usage by example), set up the firewall, install Fail2Ban, a webserver by nginx/apache2, ... Your imagination is the limit ;-) !