For most of my Linux projects, and a lot of the tutorials on this site, I fire up a virtual machine on Hyper-V and load up a minimal Debian system. Working with a Debian system gives me a stable, clean, platform I can easily customize as needed. Plus, there are numerous programs available for Debian but comparatively few are installed by default, so I get just what I need without any additional clutter. This exact base setup is what I use for my projects and what most of the Linux examples on this site are based upon, so I thought I’d give you a quick walkthrough of how to get the same setup.
I personally use Hyper-V because my main system is Windows and it’s what I use professionally most of the time so I’m comfortable with the ecosystem. You can use any virtualization platform you like, it really doesn’t matter. The focus here is one step after that point, getting the guest OS set up and ready for us to play with. So set up the VM or bare-metal system as you see fit. Quick note though, it does have to meet the Debian minimum system requirements — 512MB RAM, 5GB HDD for a super micro-build such as housing a Certificate Authority and nothing else. For a more broadly usable system, I’d go with 2-4GB RAM and at least 50GB HDD. If you’re planning on a full GUI install (MATE or something like that), then treat it like you would a real desktop system and go for at least 4GB RAM and as big an HDD as you think you need. If you’re working with a virtual machine in Hyper-V, you can always set a large HDD maximum size and use a ‘dynamic disk’ so that only what you actually use is physically allocated.
In case you’re also using Hyper-V, here’s a few options you should set to make things work properly.
- Select Generation 2 so you can use the newer drivers and install a fully modern UEFI based system.
- If you’re not sure how much RAM you’ll need, check off ‘Use Dynamic Memory for this virtual machine’ then set a reasonable minimum amount and a generous maximum amount and Hyper-V will only allocate the minimum at first but will scale up to the maximum *as needed. For robust server systems, you’ll want to plan this out carefully, allocate the real amount you actually need and NOT use Dynamic Memory.
- For initial set up, you can make it easy and choose ‘Default Switch’ as your Networking Connection for now. That way you’ll have internet access for the Debian installation.
- Virtual disk size is up to you as I covered earlier, but you can always go big here. By default, a dynamic VHDX is created and only what you use is actually allocated.
- Skip the OS install for now, you can set that up manually later.
With other virtualization platforms you’ll have to decide on your networking as per that particular platform. For Hyper-V, you can go ahead and just start with the ‘Default Switch’ (see my article: Hyper-V Default Switch – easy LAN/internet access for guest VMs) for your initial setup. That way you’ll automatically have DHCP addressing, internet and LAN access and bidirectional communication between the host and guest system. You can switch to a dedicated NAT network (see my article: Easy internet access for Hyper-V guests using NAT) later if you need to or can take the network away entirely (or switch to a ‘private network’) later if you need an air-gapped system for things like a Certificate Authority.
Get installation media
Before you can install Debian, you need to download it, right? Go over to the Debian distribution page and choose an image to download. Since our VM will have internet access via the host system, you can get the small installation image and choose your platform accordingly. In most cases, I’d assume you’re picking the amd64 installation image. This will download an ISO that you can directly load in your VM and you’re off to the races.
Assuming you’re using Hyper-V, here are some notes you should be aware of:
- Security > Secure Boot > DISABLED.
- I haven’t found a Debian distribution that has the keys necessary for Secure Boot via Hyper-V to work, so just disable it (I know, I know, security considerations… but really, this is not the biggest security concern for most practical situations).
- More recent Ubuntu distributions work with Secure Boot enabled assuming you use “Microsoft UEFI Certificate Authority”.
- Memory: If you use Dynamic Memory, set a reasonable minimum and maximum value. I generally use 2048MB min and 4096MB max (sometimes 8192MB). Do yourself a favour and calculate everything based on 1024 as your base unit. Therefore 1KB = 1024bytes, 1MB=1024KB, 1GB=1024MB.
- Processor: I like giving 2 v-cores to all my machines, but Debian is quite happy using 1 v-core for basic operations.
- SCSI Controller: You need to add a DVD drive so you can use the Debian installation ISO. I usually add this on the same controller as my main disk but on a high location number like 10. Only advanced scenarios would call for a separate controller.
- Network Adapter: Again, I usually start with the Default Switch for installatin because it’s super simple
- I need to expand the Network Adaptor > Hardware Acceleration and DISABLE virtual machine queue because it makes my network connection super super slow if I leave it enabled (default). Likely, my hardware just doesn’t support this feature. You’ll have to try it out on your system for yourself.
- If you want/need to set a fixed MAC address, etc. then go to Network Adaptor > Advanced Features
- Integration Services: I usually choose “Operating system shutdown”, “Heartbeat” and “Guest services”. I handle time synchronization within the guest VM, but time-sync with the host via integration services works also.
- Apply all your settings then go back to your Firmware and change the boot order. Don’t waste time with the Network Adapter as your first device if you don’t have that set up in your environment. I generally change this to HDD, DVD, Network and save a few seconds on each start-up 😉
- Everything else is up to you 🙂
The Debian installation is pretty straight-forward and wizard driven, so you shouldn’t have any problems. I’m only going to point out places where things differ from the defaults and with an eye to creating a base system. I generally use the text-based installer but you can use the ‘Graphical install’ if you’d prefer.
You should just let DHCP do the work here (that’s why I recommend the Default Switch on Hyper-V) so that things are easy. You can change the networking after installation as needed for your environment.
Although you can change your hostname and domain very easily after install, you should probably just set it properly in the first place, so take a second and put a little thought into this part.
Here’s one area where you might be surprised by what I’m about to recommend. I set “1234” as my passwords for the root user and the additional user the wizard creates. Why? Because it’s easy! In the post-install set up we’ll change these to proper passwords and use ssh-keys, etc. but, for now, make your life easy and just use a very simple password.
For the majority of setups you can keep things simple and just use the ‘Guided – use entire disk and set up LVM’ option for setting up your disks, especially if you’re just starting out in your Linux adventures. One note though, regardless of your experience level, I suggest you use the LVM as it gives you many more options later. Seriously, do this even if you have no idea what LVM is.
- Remember that if you choose an ‘encrypted LVM’ you’ll have to provide a password on every boot
- All files in one partition is perfectly fine for nearly all situations, especially for new users as recommended by the wizard itself. Depending on the situation, you might want to separate the /home partition, however.
- Say Yes when asked if you want to Force UEFI installation
- On the partitioning screen, you can change filesystems if you know what you are doing. Personally, I change all ‘ext4’ to ‘btrfs’ because I like some of the additional features it gives me. This is by no means necessary, however, you can just as easily accept the defaults. EXT4 is tested and very reliable.
This part is obviously up to you, but since we’re setting up a MINIMAL system, I usually only choose the following:
- SSH server
- Working directly via the Hyper-V terminal is NOT a good idea mainly because the clipboard doesn’t work between the host and guest. This is hell, unless you like manually typing complex 64 character passwords? This is also why I suggested simple passwords for now, remember? SSH is a much smoother experience.
- Standard system utilities (this saves you a ton of time by installing basic standardized software like OpenSSL).
- IF you plan on installing Apache on this system at some point, then select “web server”. I use NGINX for all my setups, so I keep that option un-selected.
- IF you really want a GUI, then save yourself some time and choose one now. On my minimal systems (like this one) I only use the command-line but, if I need a GUI for future apps I plan to install (like VSCode), I usually pick the MATE desktop.
Congrats! You’re all set up! Now, let’s get this thing a little customized and secured. Assuming you followed my advice, you can login as ‘root’ with password ‘1234’. Again, I do this because the Hyper-V console connection does NOT have clipboard functionality with the Debian command-line so pasting a complex password is impossible. Also, you only have 60 seconds to type a complex password at the prompt, so that’s pretty tough too. When we get SSH set up, you can use nice long passwords and keys to keep things safe, but for now, simple is almost necessary.
You can clone the git archive I use to store and update my configurations. This ensures you have the most recent updates, but involves you installing git on your system (which is pretty useful, actually). If space is really at a premium, however, this may not be your best choice. Here’s how you do it… Log in/switch to your root user and then: This will create a directory called ‘DebianConfigs’ in your home directory and within that is a directory called ‘configs’ that contains copies of all the files you’ll need to duplicate my base-system setup. There’s also a bash script called ‘customize.sh’ that you can run to backup your configuration files and copy mine over them automatically. (To all my American friends… ‘customize’ is how we spell ‘customise’ here in Canada). Then you can follow along with the rest of this post to customize those files or just consult the readme.md files in the git archive. Run the script as follows: Every time I make changes to my default base-system configurations, I put them together in a zip/tar ‘release’ archive that you can download and extract. This is a better option for systems where you don’t want to install git. However, the configurations may be slightly older than those in the raw git archive. Grab the latest release in your preferred format here. Extract and use the script as explained in the section above.
Option 1: Clone the git archive
apt-get install git
git clone https://git.asifbacchus.app/asif/DebianConfigs.git
Option 2: Download ‘release’ zip/tar
You can clone the git archive I use to store and update my configurations. This ensures you have the most recent updates, but involves you installing git on your system (which is pretty useful, actually). If space is really at a premium, however, this may not be your best choice. Here’s how you do it… Log in/switch to your root user and then:
This will create a directory called ‘DebianConfigs’ in your home directory and within that is a directory called ‘configs’ that contains copies of all the files you’ll need to duplicate my base-system setup. There’s also a bash script called ‘customize.sh’ that you can run to backup your configuration files and copy mine over them automatically. (To all my American friends… ‘customize’ is how we spell ‘customise’ here in Canada). Then you can follow along with the rest of this post to customize those files or just consult the readme.md files in the git archive. Run the script as follows:
Every time I make changes to my default base-system configurations, I put them together in a zip/tar ‘release’ archive that you can download and extract. This is a better option for systems where you don’t want to install git. However, the configurations may be slightly older than those in the raw git archive. Grab the latest release in your preferred format here. Extract and use the script as explained in the section above.
Your first task is to get the network set up as you will need it. In my article, Hyper-V Default Switch — easy LAN/internet access for guest VMs, I go though the times when the Default Switch is not appropriate. Those points may also apply to other virtualization platforms. Otherwise, if the network is set up the way you like you can just leave everything as-is. Most commonly, however, you need a static setup. In that case, quickly hop over to my article on Setting up a Static IP on a Debian machine and, if you’re using Hyper-V, check out my article Easy internet access for Hyper-V guests using NAT so you still have internet access if needed. After all that, come back here. (All links open new tabs).
It’s bad practice to use your root account unless absolutely necessary and even then, never by remote. In fact, your root account should ONLY be accessible via the physical/virtual console. So, let’s get sudo set up now and give our user account (created during setup) permission to use it. First, let’s install sudo:
apt-get install sudo
Great, halfway there. Sudo grants permission for it’s use to any users in the sudo group. So all we have to do is add our user to that group.
usermod -aG sudo username
That’s it. Our standard user is now part of the sudo group and can run commands as root using his/her own password. If you want to learn more about sudo, how it works and how to configure it, check our my article Installing sudo on a Debian/Ubuntu system and understanding sudoers
Now is a really good time to get SSH set up on your new VM so that you can access it easily and efficiently. This is especially true if you’re running it on a Hyper-V host since not having a clipboard is a huge PITA. Take a quick look at my article Setting up SSH with ED25519 user and host keys for easy, secure access and then come back when you’re done. Note: If you downloaded my DebianConfigs helper-archive, you already have a copy of the sshd_config file used in that article so you don’t have to type it manually 🙂
Ok, you should be able to login to your system via SSH now without passwords and without security prompts. Nice work! Most of our interactions with our system will be via SSH so we can go ahead and make our passwords super-long and very strong. This goes for not only the root password, but also any and all accounts that have sudo access because, for all intents and purposes, they are root accounts too! Now, you are correct in thinking that we will still have to input those passwords when we use sudo for root access. However, because we have bidirectional clipboard access via SSH (which we didn’t have with the Hyper-V console) we can store those long passwords securely in a password manager and copy/paste them when needed. Make sense? Even if you choose not to go this route, we still MUST change our passwords from ‘1234’.
Log in as your user-account (SSH or console) and type the following:
You’ll be prompted for your current password, a new password and then asked to confirm your new password. Let’s change our root password by first changing to the root account:
Now, just like with our user account, change the password:
You’ll be prompted for the new password and asked to confirm it (current password is unnecessary). That’s it, passwords updated! Now, don’t forget them!
Prompts, Colourization & Aliases (OPTIONAL SECTION)
N.B. Although your customizations have been applied, the user account created by the installation wizard will NOT have been updated, as you may or may not have already noticed. This is because the account’s ~/.bashrc was already created and not copied from /etc/skel/.bashrc. Let’s fix that… by the way, the fix is the same for any user account that has not inherited the new settings from the skeleton profile. Log in as that user and then: That’s it — log out and back in and you’ll see the shiny new prompt. If you need to do this for your root account for some reason, you must copy the .bashrc file from the helper archive’s config/root/.bashrc and not use the skeleton profile since it’s a different setup for your root account versus user accounts.
cp /etc/skel/.bashrc ./
N.B. Although your customizations have been applied, the user account created by the installation wizard will NOT have been updated, as you may or may not have already noticed. This is because the account’s ~/.bashrc was already created and not copied from /etc/skel/.bashrc. Let’s fix that… by the way, the fix is the same for any user account that has not inherited the new settings from the skeleton profile. Log in as that user and then:
That’s it — log out and back in and you’ll see the shiny new prompt.
If you need to do this for your root account for some reason, you must copy the .bashrc file from the helper archive’s config/root/.bashrc and not use the skeleton profile since it’s a different setup for your root account versus user accounts.
This section is not really critical, but it does make working on your system a lot easier, faster and a little safer especially when performing actions as root. We’ll be creating a more informative and colourful prompt, then adding some colour to our directory displays so you can tell different files and directories apart at a glance and finally, adding some command aliases to cut down on how much we type.
The default prompt is not bad, but I like a little more detail in my prompt and some colour. Most important, I like to be reminded if I’m working as a normal user or as a root user. So, I set my prompt to display the time, my username and machine hostname and the current working directory. In addition, I like my username to be in red if running as root or green if I’m running as a regular user.
There are several ways to set a custom prompt, but I like to use /etc/bash.bashrc for the reasons I outlined in my article Custom prompt and command aliases: Why I choose bash.bashrc. So open /etc/bash.bashrc and add the following to the end of the file:
# Test for root and change prompt username to RED, otherwise username is GREEN force_color_prompt=yes if [ $(id -u) -eq 0 ]; then PS1='[$(date +%H:%M)] \[3[00;31m\]\u\[3[00m\]@\[3[00;33m\]\h\[3[00m\]:\w$ ' else PS1='[$(date +%H:%M)] \[3[00;32m\]\u\[3[00m\]@\[3[00;33m\]\h\[3[00m\]:\w$ ' fi
Complicated, right? Not really, but I’m not going to explain it much either. The reason is that it’s easier to see it for yourself (if you’re interested) by constructing a prompt on your own using a configuration generator. That way you can understand each of the ANSI colour escape codes and the prompt escape codes. Go take the Easy Bash Prompt Generator for a test drive and you’ll see what I mean. Hey, you might even make something you like more than mine and you can substitute that PS1= code into your /etc/bash.bashrc file! If you create a really cool prompt, let me know in the comments and I’ll link it up on the site 🙂
If you are playing with different prompts, you don’t have to login and logout to see your changes. Simply type the following after saving your changes in /etc/bash.bashrc:
That will refresh your prompt instantly and you can bask in your glorious new prompt or fix any mistakes you’ve made!
Colourize directory listings
This one is super useful and let’s you see at-a-glance which names are directories, which files are executable, etc. on every directory listing. Again, I like making this change in /etc/bash.bashrc. Open it up and append this to the end:
# Colourize directory listing export LS_OPTIONS='--color=auto' eval "`dircolors`"
Quick note: Those are backticks around ‘dircolors’. The backtick is the key next to your “1” key on your keyboard that also has the tilde (~) symbol. It’s like the weird cousin of the single-quote but has a special meaning in Linux. Make sure you use double-quote backtick dircolors backtick double-quote or it won’t work.
Again, you can immediately enact this change using the source trick we learned in the previous section or just log out and back in then generate a directory listing using ‘ls’.
Command aliases are incredible. They let you define what you type to execute whatever commands you want (within reason). I like using them to define stuff like exactly how my directory listings appear, for example, so I can just type ‘l’ instead of ‘ls -lAsh –group-directories-first’. You can set up any aliases you like using my examples as a reference. Again, I use put them in /etc/bash.bashrc but you can also quite reasonably put them in ~/.bashrc so they only affect your user account. Open which ever file you prefer and append your aliases to the end of the file. I use these, as an example:
# Command aliases alias ll='ls $LS_OPTIONS -l' alias l='ls $LS_OPTIONS -lAsh --group-directories-first' alias ld='ls $LS_OPTIONS -ldsh' alias rm='rm -i' alias mv='mv -i' alias cp='cp -i'
You can see the basic structure is the alias (i.e. what you type) on the left and then what it means on the right. In my example, I add the -i (‘interactive’) flag to all my copy, move and and delete commands so I have to confirm each file. This stops me accidentally overwriting or carelessly deleting files without a second-thought. Go ahead an add as many or as few aliases as you like.
Once again, you can immediately enact these changes by re-sourcing your /etc/bash.bashrc or your ~/.bashrc, depending on which one you changed, or just logging out and back in again.
NTP time synchronization
Especially if you’re running a server, time synchronization is pretty important. Fortunately, it’s also really easy to get running. All recent versions of Debian use systemd-timesyncd instead of the full-fledged ntpd package and this is just fine. Configuration is handled via a configuration file and the timedatectl command. Here’s a quick overview of key files and commands:
All we should need to do is update the configuration file to use the NTP servers we want and then restart the service. If you downloaded the helper-archive and ran the customization.sh script, then the template file has been copied for you. If not, the default file is easy enough to modify. Either way, open /etc/systemd/timesyncd.conf and edit the NTP= to list the timeservers you wish to use, separated by spaces. If you need help finding a timeserver to use, check out the NTP.org list page and browse to the geographically closest area then use those timeservers. They are free, accurate, used by millions and very safe. I’m in Canada, so I generally use the National Research Council’s timeservers (in the US you might use NIST servers, for example). When you’re done editing your file, the last few lines should look something like this:
NTP=time.nrc.ca time.chu.nrc.ca FallbackNTP=0.ca.pool.ntp.org 1.ca.pool.ntp.org 2.ca.pool.ntp.org 3.pool.ntp.org
In this case, I’ve used the NRC timeservers as my primary and the NTP.org servers for Canada as my fallback servers. The fallback servers are completely optional. You’ll notice in the default file they are commented out, you can leave it this way if you like. An equally valid setup would be something like this:
NTP=0.ca.pool.ntp.org 1.ca.pool.ntp.org 2.ca.pool.ntp.org 3.pool.ntp.org #FallbackNTP=0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org 3.debian.pool.ntp.org
This is pretty much the default file with the NTP servers updated.
Once that’s done, save the file and restart your timesyncd service.
systemctl restart systemd-timesyncd.service systemctl status systemd-timesyncd.service
You should see that the service is ‘running’ and is reporting that it is synching to one of the servers that you have specified. We need to check one more thing just to be completely sure things are working:
This should show the correct time (haha) and should also state NTP synchronized: yes. If it does not, then you may have to run this command:
timedatectl set-ntp TRUE
After that restart the service as we did above then check it’s status one more time by running ‘timedatectl’. Everything should be working now.
Configure nano (OPTIONAL)
The last thing I like doing on my base-systems is to set up Nano with some useful defaults. As you may have noticed, I like using Nano for all my editing. I find vi too cumbersome and think that Nano does a great job of balancing features and ease of use. Ultimately it’s up to you. I like setting Nano to open multiple files at once, display line numbers, auto-match brackets and quotes, auto-indent and I map a few custom keystrokes.
If you downloaded the helper-archive and ran the customize.sh script, then all these changes have been done for you. If you just want the updated Nano configuration, grab it here. There’s too many changes to go into individually but, you can diff the default vs my changes and see what options I’ve enabled. I will, however, quickly summarize the keyboard shortcuts that I added:
Well, that’s finally it — exactly how I set up my Linux base-systems. Virtually every other tutorial you’ll find on this site that uses a Debian server starts with this exact setup. I know this has been a loooong article and thank you for sticking it out to this point. I hope this has given you a clear set of instructions on how to set up a solid Debian-base system. Using this setup, you can add components and programs to quickly create a webserver, WordPress system, git server, certificate authority, and so many other things — enjoying experimenting! Thanks for reading my techie-thoughts on this issue. Have any comments? Suggestions? Want to add your tips? Things you want me to cover in a future article? Comment below!