{"id":3847,"date":"2025-04-25T14:58:19","date_gmt":"2025-04-25T13:58:19","guid":{"rendered":"https:\/\/raspberry-projects.com\/pi\/?p=3847"},"modified":"2025-11-16T17:52:26","modified_gmt":"2025-11-16T17:52:26","slug":"setting-up-a-secure-ubuntu-server","status":"publish","type":"post","link":"https:\/\/raspberry-projects.com\/pi\/pi-operating-systems\/ubuntu-servers\/setting-up-a-secure-ubuntu-server","title":{"rendered":".Setting up a secure Ubuntu server"},"content":{"rendered":"\n<p class=\"has-text-align-center\"><a href=\"https:\/\/ibex.tech\/under-the-hood\/creating-a-secure-cloud-server-for-blockchain-transaction-signing\" target=\"_blank\" rel=\"noreferrer noopener\">The backstory that prompted this page &#8211; ibex.tech\/under-the-hood<\/a><\/p>\n\n\n\n<p>A Raspberry Pi running Ubuntu makes a great little server for the internet. You could use Raspberry Pi OS, but Ubuntu has become a pretty standard choice for Linux servers on the internet so arguably better to use that to maximise chances of avoiding security vulnerabilities.<\/p>\n\n\n\n<p>These instructions apply to any server running Ubuntu, not just a RPi of course.<\/p>\n\n\n\n<p>These are our steps to take from fresh Ubuntu server OS install, to secure and ready to use in 10 minutes. Here&#8217;s what we&#8217;ll do:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Use our normal Windows desktop operating system to access the Ubuntu server and perform all the setup.<\/li>\n\n\n\n<li>Change the default root password.<\/li>\n\n\n\n<li>Change the user account setup to optimise security.<\/li>\n\n\n\n<li>Setup SSH to use a keypair and password for login, for optimum security.<\/li>\n\n\n\n<li>Setup the firewall to ensure Ubuntu isn&#8217;t listening on any unnecessary ports.<\/li>\n<\/ul>\n\n\n\n<p>Once all that is done you&#8217;ll have a super secure ready to go Linux server.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Log in via SSH<\/h4>\n\n\n\n<p>Your Ubuntu server can be connected to using SSH. This is the standard protocol used to give you command line access to the Linux OS, as if you had a keyboard and monitor plugged into it directly.<\/p>\n\n\n\n<p>You&#8217;ll need to use a program to connect using SSH. <a href=\"https:\/\/www.putty.org\/\" data-type=\"link\" data-id=\"https:\/\/www.putty.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">PuTTY<\/a> is a great open source tool for it. We use <a href=\"https:\/\/mobaxterm.mobatek.net\/\" target=\"_blank\" rel=\"noreferrer noopener\">MobaXterm<\/a> as it gives us a few nice features, but any decent SSH software will do.<\/p>\n\n\n\n<p>Note, to paste text into the SSH terminal: CTRL+right mouse click usually works.<\/p>\n\n\n\n<p>Connect to your Ubuntu server using SSH, port 22, username (likely root) and password.<\/p>\n\n\n\n<p>You should get a welcome message. All of the instructions below assume you have connected and have the Linux command line showing ready to take an instruction.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Ensure everything is up to date<\/h4>\n\n\n\n<p>Update the Linux OS and all the installed applications. (You want to always do this before making software changes to the server).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apt-get update &amp;&amp; apt-get upgrade<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Checking out your new server setup<\/h4>\n\n\n\n<p>Optional, if you want to have a look and make sure you&#8217;ve got what you were expecting&#8230;<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Get operating system info<\/h5>\n\n\n\n<pre class=\"wp-block-code\"><code>uname -a<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">View Linux system hardware information<\/h5>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo lshw<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">View Linux CPU Information<\/h5>\n\n\n\n<pre class=\"wp-block-code\"><code>lscpu<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">View storage devices information<\/h5>\n\n\n\n<pre class=\"wp-block-code\"><code>lsblk<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Setting a new root password<\/h4>\n\n\n\n<p>If you didn&#8217;t create it (install the OS yourself) you want to change the root users password, ensuring you use something <a href=\"https:\/\/www.grc.com\/passwords.htm\" target=\"_blank\" rel=\"noreferrer noopener\">nice and secure<\/a>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo passwd root<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Account security checks<\/h4>\n\n\n\n<h5 class=\"wp-block-heading\">Ensure only root has UID set to 0 (highest access to the system)<\/h5>\n\n\n\n<pre class=\"wp-block-code\"><code>awk -F: '($3==\"0\"){print}' \/etc\/passwd<\/code><\/pre>\n\n\n\n<p>You should only get the root account shown.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Check for accounts with empty passwords<\/h5>\n\n\n\n<pre class=\"wp-block-code\"><code>cat \/etc\/shadow | awk -F: '($2==\"\"){print $1}'<\/code><\/pre>\n\n\n\n<p>You should get no accounts shown.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">root user<\/h5>\n\n\n\n<p>It\u2019s best practice to keep use of the root account to a minimum. So we will create a new account that we&#8217;re going to use day to day. In our example we&#8217;re going to give it the name: admin<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>adduser admin<\/code><\/pre>\n\n\n\n<p>Enter a <a href=\"https:\/\/www.grc.com\/passwords.htm\" target=\"_blank\" rel=\"noreferrer noopener\">good password<\/a>.<\/p>\n\n\n\n<p>Full name etc, you can just press enter to leave these bank.<\/p>\n\n\n\n<p>The sudo command allows a regular user to run commands in an elevated context. This means our regular admin user can run commands normally restricted to the root account. This is the ideal way of making system configurations or running elevated commands, instead of using the root account itself. <\/p>\n\n\n\n<p>The configuration file for sudo is in \/etc\/sudoers. However, it can only be edited by using the \u201cvisudo\u201d command. There are many different configuration options that limit the use of sudo to certain users, groups, IPs, and commands. The general configuration format is below:<\/p>\n\n\n\n<p>Set user admin to be a sudo user:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>usermod -aG sudo admin<\/code><\/pre>\n\n\n\n<p>Verify it using:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>id admin<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Disable root login<\/h4>\n\n\n\n<p>Close the SSH connection and reconnect using the new admin account you created, instead of root (apart from anything else, to check it works before we disable root login).<\/p>\n\n\n\n<p>We&#8217;re going to edit the SSH configuration file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nano \/etc\/ssh\/sshd_config<\/code><\/pre>\n\n\n\n<p>Find the line with &#8220;PermitRootLogin&#8221;, remove the &#8216;#&#8217; character at the start of the line if present and change it to no:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>PermitRootLogin no<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">Allow user admin<\/h5>\n\n\n\n<p>Find the line with AllowUsers to set it to allow our new admin user, or if its missing add it like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>AllowUsers admin<\/code><\/pre>\n\n\n\n<p>Save and exit the config file (CTRL+S, CTRL+X)<\/p>\n\n\n\n<p>Restart the SSH service to apply the changes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo service ssh restart<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Use a key pair for SSH login<\/h4>\n\n\n\n<p>Using a public and private key pair for SSH login is a highly recommended security step, much more secure than using password login.<\/p>\n\n\n\n<p>Create a key pair, on Windows open the command prompt and enter:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ssh-keygen<\/code><\/pre>\n\n\n\n<p>Enter a filename for your keys with no extension (e.g. &#8220;server001&#8221;)<br>Enter a password if you want to use one (not required, but good security to use one, so that obtaining the keyfile alone won&#8217;t let a hacker in).<\/p>\n\n\n<p>2 files are generated, they will have probably been written to: C:\\Users\\YOUR_USER_NAME\\<\/p>\n<p>The files:<\/p>\n<p style=\"padding-left: 40px;\">server001 (the private key &#8211; rename it to &#8220;server001_private_key.pem&#8221;<\/p>\n<p style=\"padding-left: 40px;\">server001.pub (the public key &#8211; rename it to &#8220;server001_public_key.pem&#8221;<\/p>\n<p>So you should now have<\/p>\n<p style=\"padding-left: 40px;\">server001_private_key.pem<\/p>\n<p style=\"padding-left: 40px;\">server001_public_key.pem<\/p>\n\n\n<h5 class=\"wp-block-heading\">Adding the public key to the Ubuntu server<\/h5>\n\n\n\n<p>Open your &#8220;server001_public_key.pem&#8221; file and copy the entire string, e.g.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ssh-ed25519 AAAAC3NzaC15ZDI1NTE5AAAAIBjjwGQWHOrZQ44QgUdvxfSUOW20aeC7yxOzKVlXiNWi john@John-Dell7340<\/code><\/pre>\n\n\n\n<p>You will replace &#8220;PASTE_YOUR_PUBLIC_KEY_STRING_HERE&#8221; with it below<\/p>\n\n\n\n<p>Now on the server command line enter:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir -p ~\/.ssh\n\necho PASTE_YOUR_PUBLIC_KEY_STRING_HERE &gt;&gt; ~\/.ssh\/authorized_keys<\/code><\/pre>\n\n\n\n<p>Configure permissions for the ~\/.ssh directory and the authorized_keys file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>chmod -R go= ~\/.ssh<\/code><\/pre>\n\n\n\n<p>Now, disconnect and try connecting setting your SSH application to use your private keyfile &#8220;server001_private_key.pem&#8221;, instead of the admin account password. If you are using MobaTerm, delete the root password if you let it save it and then in Session settings &gt; Advanced SSH settings &gt; User private key = Checked. Select your keyfile &#8220;server001_private_key.pem&#8221;<\/p>\n\n\n\n<p>Now connect, you should be prompted for the password you used when creating the keyfile and you should then be back connected to your Ubuntu server via SSH.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Disable password login<\/h4>\n\n\n\n<p>Now that you&#8217;ve proved your keypair is working, ensure you have backed up your private keyfile &#8220;server001_private_key.pem&#8221; and its password (if you loose either you won&#8217;t be able to connect to the Ubuntu server again). Then in Ubuntu, open the SSH key settings<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nano \/etc\/ssh\/sshd_config<\/code><\/pre>\n\n\n\n<p>Find the line containing &#8220;PasswordAuthentication&#8221;, remove the &#8216;#&#8217; at the start of the line if its present and set it to no, so you should have:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>PasswordAuthentication no<\/code><\/pre>\n\n\n\n<p>Save and exit the config file (CTRL+S, CTRL+X)<\/p>\n\n\n\n<p>For Ubuntu\/Debian you also need to do the same thing in this file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nano \/etc\/ssh\/sshd_config.d\/*.conf<\/code><\/pre>\n\n\n\n<p>Thats it. Restart the service to apply the configuration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo service ssh restart\nsudo service sshd restart<\/code><\/pre>\n\n\n\n<p>You will be unable to login without using your private key now.<\/p>\n\n\n\n<p>That&#8217;s the user account and SSH logging security steps complete. You&#8217;re server is now really well protected from someone unauthorised getting in via SSH.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Firewall (Iptables)<\/h4>\n\n\n\n<p>To make the servers Ethernet conneciton as secure as possible, you should lock down your firewall ports so you&#8217;re only exposing the ones absolutly necessary to the internet.<\/p>\n\n\n\n<p>Only allowing incoming connections on ports 22 (SSH), 80 (HTTP), 443 (HTTPS) and the loopback interface.<\/p>\n\n\n\n<p>You&#8217;ll need the iptables-persistent package installed:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apt-get install iptables-persistent<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">Configure rules for IPv4<\/h5>\n\n\n\n<p><strong><em>Warning &#8211; if you do this and don&#8217;t add the port 22 SSH rule you&#8217;ll lock yourself out of your server!<\/em><\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo iptables -A INPUT -i lo -j ACCEPT\n\nsudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT\n\nsudo iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT\n\nsudo iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT\n\nsudo iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT\n\nsudo iptables -P INPUT DROP\n\nsudo -i\niptables-save &gt; \/etc\/iptables\/rules.v4\nexit<\/code><\/pre>\n\n\n\n<p><em>Note that the &#8220;-i lo&#8221; loopback line is needed, without it apt get, ping, etc will not work.<\/em><\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Viewing the current Iptable rules toconfirm your changes<\/h5>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo iptables -L\nsudo iptables -S<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">Configure rules for IPv6<\/h5>\n\n\n\n<p>We&#8217;re just going to block all incoming IPv6 connections<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ip6tables -P INPUT DROP\n\nsudo -i\nip6tables-save > \/etc\/iptables\/rules.v6\nexit<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Thats it!<\/h4>\n\n\n\n<p>Your Ubuntu server is locked down using all the standard best practices. The firewall is setup ready for you to use with whatever <a href=\"https:\/\/raspberry-projects.com\/pi\/pi-operating-systems\/ubuntu-servers\/install-apache-php-and-mysql\">web server components you&#8217;re going to install<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Any issues?<\/h4>\n\n\n\n<p>Think there&#8217;s something we could have done better (whilst keeping things simple)? Think we&#8217;ve made a mistake? Drop a comment below&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The backstory that prompted this page &#8211; ibex.tech\/under-the-hood A Raspberry Pi running Ubuntu makes a great little server for the internet. You could use Raspberry Pi OS, but Ubuntu has become a pretty standard choice for Linux servers on the internet so arguably better to use that to maximise chances of avoiding security vulnerabilities. These [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[200],"tags":[],"class_list":["post-3847","post","type-post","status-publish","format-standard","hentry","category-ubuntu-servers"],"_links":{"self":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts\/3847","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/comments?post=3847"}],"version-history":[{"count":37,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts\/3847\/revisions"}],"predecessor-version":[{"id":3989,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts\/3847\/revisions\/3989"}],"wp:attachment":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/media?parent=3847"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/categories?post=3847"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/tags?post=3847"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}