Post

How to Set Up a Server for Development (Linux Ubuntu)

How to Set Up a Server for Development (Linux Ubuntu)

This guide is divided into two main parts:

  1. Setting up the server with all essential configurations (OS installation, networking, firewall, SSH, etc.)
  2. Cloning the repository and setting up development dependencies (Git with Github, CI/CD pipeline, and personal self-hosting environment)

By following these steps, you’ll have a fully configured server ready for development.


Part 1: Server Setup and Configuration

1. Prepare Bootable Drive

Before you begin installing the operating system, you’ll need to create a bootable drive to install the OS. This drive will contain the OS installation files.

  • Choose a USB drive or external disk: Ensure the drive has enough capacity to hold the OS installer. A drive with at least 4 GB of free space is recommended.
  • Download your desired Linux distribution: Go to the Ubuntu Server download page and download the latest Ubuntu LTS version (recommended). Make sure you’re downloading the server version of your Linux distribution, as this is optimized for headless (non-GUI) environments.
  • Create a bootable drive: After the download, you need to write the installer to the USB drive using a tool like Rufus (recommended for Windows users), Etcher, or dd (for Linux). Here’s how to use Rufus:
    1. Download and install Rufus from here.
    2. Plug your USB drive into your PC.
    3. Open Rufus and select the USB drive in the “Device” dropdown.
    4. Under “Boot selection,” click Select and browse for the Ubuntu ISO file you just downloaded.
    5. Choose GPT for partition scheme and UEFI for target system.
    6. Click Start to begin the process. Once complete, your USB drive will be bootable and ready for installation.
  • Set the USB drive to boot: Once the bootable USB drive is ready, plug it into your server and reboot it. Make sure your server’s BIOS/UEFI settings are configured to boot from the USB device. This is usually done by pressing a key like F2, F12, or ESC during startup to access the boot menu.
  • Connect a keyboard and monitor: Since you’re setting up a server and this is the initial installation, you’ll need to connect both a keyboard and monitor to the server. The monitor will display the installation process, and the keyboard will allow you to input necessary information.
  • Begin installation: After rebooting, your server should automatically detect the USB drive and start the Ubuntu installer. Follow the on-screen instructions carefully to install Ubuntu. During the installation process, make sure to:
    1. Select your language and keyboard layout.
    2. Set up disk partitioning. For most cases, the default partition scheme should work, but make sure to format the disk according to your needs.
    3. Configure basic network settings (either through Ethernet or Wi-Fi) and establish at least a temporary connection. This is vital for installing the full NetworkManager later during the installation process. If you skip this step, you’ll need to manually configure the Netplan file, which can be tedious, error-prone, and difficult for beginners.

Once the installation is complete, the server will prompt you to reboot. Before doing so, make sure to remove the USB drive to prevent the system from booting back into the installer.


2. Set Up Temporary Network Connection

Run:

1
ip a

If your network was set up during installation and you see an assigned IP, skip to here.

If networking was not set up during installation We need to configure a temporary network connection manually.

  1. Find your network interface name
1
ip a
  • If using Ethernet, look for an interface starting with eth or enp (e.g., eth0, enp3s0).
  • If using Wi-Fi, look for an interface starting with wlan or wlp (e.g., wlan0, wlp2s0).
  1. Edit the Netplan configuration file
1
sudo nano /etc/netplan/01-netcfg.yaml
  1. Configure Ethernet (Replace eth0 with your actual interface name):
1
2
3
4
5
6
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0: # Replace with your Ethernet interface name
      dhcp4: true

OR

Configure Wi-Fi (Replace wlan0 with your actual interface name and update SSID/PASSWORD):

1
2
3
4
5
6
7
8
9
network:
  version: 2
  renderer: networkd
  wifis:
    wlan0: # Replace with your Wi-Fi interface name
      dhcp4: true
      access-points:
        "SSID":
          password: "PASSWORD"
  1. Apply changes and restart networking
1
2
sudo netplan apply
sudo reboot
  1. Verify connection after reboot
1
ip a

You should now see a valid connection with:

  • An internal IP address (e.g., 192.168.x.x or 10.x.x.x) assigned to your interface.
  • The interface name you configured (eth0, wlp2s0, etc.) showing as UP.

3. Ensuring a Stable Network Connection

Now that the default network configuration is working, the next step is to keep the network always up and consistent. This is crucial to prevent unexpected disconnections and ensure SSH access remains available at all times, even after reboots or network changes.

To achieve this, we will:

  1. Configure a static IP address so the server always uses the same local IP, preventing issues with dynamic address changes.
  2. Set a persistent network interface name to avoid inconsistencies when the system renames interfaces on reboot.

To simplify network management, we will use NetworkManager, which makes it easier to configure and maintain network settings compared to manually editing Netplan files.

Step 1: Install NetworkManager

Now that networking is working, install NetworkManager:

1
2
sudo apt update
sudo apt install network-manager

Step 2: Connect to Wi-Fi

Once NetworkManager is installed, you can use it to connect to your network. Run the following command to connect to your Wi-Fi network. Replace SSID_NAME with the name of your Wi-Fi network and YOUR_PASSWORD with your network’s password:

1
sudo nmcli device wifi connect "SSID_NAME" password "YOUR_PASSWORD"

For Ethernet connections, if NetworkManager is properly set up, it should automatically manage the connection without needing a specific command. If not, you can use similar nmcli commands to manage the Ethernet connection.

Step 3: Set a Static IP Address

After you’ve successfully connected to your Wi-Fi (or Ethernet), the next step is to configure a static IP address. Run the following command to modify your network settings, replacing 192.168.2.X with the static IP you want for your local internal IP address, 192.168.2.1 with your network gateway, and 8.8.8.8, 1.1.1.1 with your DNS servers (if needed):

1
sudo nmcli connection modify "Wi-Fi" ipv4.method manual ipv4.addresses 192.168.2.X/24 ipv4.gateway 192.168.2.1 ipv4.dns "1.1.1.1,8.8.8.8" connection.autoconnect yes
  • ipv4.addresses 192.168.2.X/24: Replace 192.168.2.X with your desired static internal IP address.
  • ipv4.gateway 192.168.2.1: Replace 192.168.2.1 with your network gateway (usually your router’s IP).
  • ipv4.dns "1.1.1.1,8.8.8.8": This sets custom DNS servers; you can omit this or use your router’s IP if you prefer not to use public DNS.
  • connection.autoconnect yes: Ensures that the network connection is set to auto-connect.

Note: The gateway is typically required for external communication (e.g., accessing the internet). If you are setting up a local-only network, you may omit the gateway setting.

This configures your network connection to use a manual static IP address instead of relying on DHCP.

Step 4: Restart NetworkManager

Once the settings are updated, restart NetworkManager to apply the changes:

1
sudo systemctl restart NetworkManager

Your server should now have a static IP address, which should be persistent even after reboot.

Step 5: Set a Static Network Interface Name

To prevent the network interface name (e.g., wlp4s0) from changing after each reboot, you will create a custom udev rule. This ensures the interface name stays consistent. Create a new udev rule file following the required naming convention: NN-Description.rules, where NN represents a two-digit number and Description is a meaningful identifier for the rule:

1
sudo nano /etc/udev/rules.d/99-network-config.rules

Add the following lines to bind a specific MAC address to the interface name wlp4s0 (you can replace wlp4s0 with your desired interface name):

1
2
ACTION=="add", SUBSYSTEM=="net", ATTR{address}=="XX:XX:XX:XX:XX:XX", NAME="wlp4s0", \
   RUN+="/usr/bin/ip link set dev %k address XX:XX:XX:XX:XX:XX"
  • ATTR{address}=="XX:XX:XX:XX:XX:XX": Replace XX:XX:XX:XX:XX:XX with the original MAC address of your network interface.
  • NAME="wlp4s0": This sets the network interface name to wlp4s0. You can change this to another name depending on your needs.
  • RUN+="/usr/bin/ip link set dev %k address XX:XX:XX:XX:XX:XX": This allows to set a custom MAC address (different from the original one) for the interface.

    Note: The last line (RUN+="/usr/bin/ip link set dev %k address XX:XX:XX:XX:XX:XX") is only needed if you want to use a second MAC address on top of your original one. For example, if your network blocks your device, it could block your MAC address, but by switching to a new one, you’ll remain connected. Yes, I had to do that.

Once the rule is added, save and exit the file.

Step 6: Restart Network Services

After editing the rules file, restart your system or network service for the changes to take effect:

1
2
sudo systemctl restart systemd-udevd
sudo systemctl restart NetworkManager

After completing these steps, your server will have a static IP address and a consistent network interface name, even after reboots.


4. Set Up UFW (Uncomplicated Firewall)

It’s important to configure a firewall to secure your server. Here’s how to set up a simple firewall using UFW:

  1. Install UFW if it’s not already installed (comes by default with ubuntu):

    1
    
    sudo apt install ufw
    
  2. Configure UFW:
    • Block all incoming traffic by default:
      1
      
      sudo ufw default deny incoming
      
    • Allow outgoing traffic:
      1
      
      sudo ufw default allow outgoing
      
    • Allow SSH (port 22) for remote connections:
      1
      
      sudo ufw allow 22
      
    • If you’re using a custom SSH port (e.g., for obfuscation), allow it instead:
      1
      
      sudo ufw allow [YOUR_CUSTOM_PORT]
      
  3. Enable UFW to apply the changes:
    1
    
    sudo ufw enable
    
  4. Check UFW status to confirm your firewall settings: bash sudo ufw status You should now have a basic firewall configuration that restricts all unnecessary traffic, allowing only essential services (such as SSH or specific custom ports). Remember, the fewer ports you leave open, the more secure your system should be.

5. Setup SSH for Remote Access

  • Install the openssh-server package if it’s not already installed:
    1
    2
    
    sudo apt update
    sudo apt install openssh-server
    
  • Ensure the SSH service is enabled and running:
    1
    2
    
    sudo systemctl enable ssh
    sudo systemctl start ssh
    
  • Create SSH keys on your local machine (if not already created):
    1
    
    ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
    
  • Copy the public key to the server to enable passwordless SSH login:
    1
    
    ssh-copy-id user@your_server_ip
    
  • Optionally, configure SSH to disable password authentication for additional security by editing the /etc/ssh/sshd_config file and setting PasswordAuthentication no. - Restart SSH service: bash sudo systemctl restart ssh More info can be found here.

This is the time where you can disconnect your keyboard and monitor from your server and have full remote access from your other device


Part 2: Final Repository Installation

6. Set Up Git with GitHub

  • Ubuntu typically comes with Git pre-installed. If it’s missing, install it:

    1
    
    sudo apt install git
    
  • Configure your Git username and email:

    1
    2
    
    git config --global user.name "Your Name"
    git config --global user.email "your_email@example.com"
    
  • Generate an SSH key if you don’t already have one, and add it to your GitHub account:

    1
    2
    3
    
    ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
    ssh-add ~/.ssh/id_rsa
    cat ~/.ssh/id_rsa.pub
    
  • Copy the output of cat ~/.ssh/id_rsa.pub and add it to GitHub > Settings > SSH and GPG keys.

7. Clone and Install the Server Repository

  • Clone your server repository and enter its directory:

    1
    2
    
    git clone git@github.com:your_username/servers.git
    cd servers
    
  • Run the installation script:

    1
    
    ./install.sh
    

Note: This is my personal setup that automates my entire development environment. It includes:

  • A CI/CD pipeline with GitHub self-hosted runners
  • Integration with Tailscale for networking
  • A proxy configured for Tailscale that manages my Docker services, like my self-hosted bookmarks and management tools

I recommend considering a similar approach if you’re comfortable with scripting and want to automate and back up your systems. However, be aware that this approach requires writing Bash scripts and maintaining your setup over time.

I’ve documented my process in detail in this article.


Notes:

  • Backup: Always back up critical files and configurations in case the server crashes or needs to be rebuilt.
  • Security: Store SSH keys and passwords securely. Avoid using root accounts for general usage.
This post is licensed under CC BY 4.0 by the author.