Linux

Linux is a free and open source Operating System (OS). It is the dominating OS on servers nowadays.

Origin

In 1970s, the Bell labs developed an OS named Unix, and it led to a standardization called Portable Operating System Interface (POSIX) to ensure compatibility among different systems.

In 1987, an OS named Minix was developed based on Unix and gained popularity in the academic field. However, the redistribution of its code was restricted. This motivated a Finnish software developer, Linus Torvalds, to developed his own OS kernel, Linux, in 1991, using the C programming language.

Linux was advertised as a free and open source software under the GNU (GNU's Not Unix) General Public License (GPL) 2.0 license. It was free to distribute, modify, and make money from it.

Distribution

A Linux distribution is a complete operating system built on top of the Linux kernel and each distribution has its own highly opinionated set of default software. Here are some famous distributions.

Bootup

The kernel acts as a bridge between the hardware and software. When we press the power button of a computer:

Control group

Control group (cgroup) is a logical box that holds the resource limits of a process, i.e., defining the maximum amount of CPU, memory, and I/O a process can use.

Namespace

A Linux namespace is a kernel-defined logical box that holds a specific software resource for a process or a group of processes within the namespace. A namespace creates a lightweight and isolated environment.

Namespace types

Process

A process is a running instance of a program that consists of an isolated memory address space and the execution of some code. When we execute a command like ls or python script.py, the Linux kernel creates a process to execute the code.

Each process is given the following resources.

Processes have a parent-child hierarchy as a parent process can start a child process.

Rings

Linux uses rings to administer operation privileges.

GNU and shell

In 1983, Richard Stallman started the GNU project to provide binaries that make the kernel useful.

Frequently-used Bash commands

Filesystem

Linux's ext4 filesystem follows the Filesystem Hierarchy Standard (FHS) 3 specification and has the following structure:

Storage devices in filesystem

File permissions

Encoding

Memory management

Networking

Routing table

A routing table stores a list of route entries. Each route entry has the following information.

NAT table

A NAT table stores the packet to IP mapping and is often used by routers.

For an outbound request from a device on the private network to an external public IP, it uses the NAT table to record the request ID to device private IP mapping, and then replaces the request's source private IP with its own public IP. When it receives a response, it use the NAT table to redirect the response to the device.

For inbound traffic, it uses the NAT table to map the inbound request's destination port to the correct device's internal IP and port on the private network.

Network device

A network device (network interface) is an abstract interface for data transmission. Its driver registers itself with the kernel and the kernel adds it to the network namespace. It acts as a bridge between the kernel and the physical hardware like an Ethernet port or Wi-Fi card, and provides a standardized way for the kernel to send and receive data. A network device is not a file, unlike many other Linux objects such as disks (/dev/sda) or serial ports (/dev/ttys0).

Network device type

Socket

A socket is a file in Linux that serves as a software endpoint for sending and receiving data. Its external address is defined by a combination of an IP address, a port number, and a protocol.

Traffic flow

When our application on Linux wants to send a request to a remote server.

  1. Application layer
    • Our application sends the request to the kernel.
  2. Transport layer
    • The kernel encapsulates the request into a segment by adding TCP headers to the request.
  3. Network layer
    • The kernel builds a packet from the segment by wrapping it with IP headers. It then forwards the packet to the specific network device like eth0.
  4. Data link layer
    • The network device driver packages the packet into a frame.
  5. Physical layer
    • The network device driver converts the frame into electronic signals and hands over the signals to a physical Network Interface Card (NIC) for transmission and the NIC sends it out.

Ubuntu

Dual boot

Assume we have a computer already installed with Windows, then we can install Ubuntu alongside it. Below are the steps of installation.

  1. Make a bootable USB drive.
    1. Download the latest LTS Ubuntu Desktop ISO image from the official website.
    2. Use a software like Rufus to write the ISO image to an USB drive.
  2. Create a disk partition.
    1. Use the Windows built-in disk management software to create an unallocated partition.
  3. Reboot from the USB drive and install Ubuntu.
    1. Restart the computer and select the USB drive for booting. Follow the prompted instructions to install the system.
    2. After the installation, reboot the computer.
    3. During the installation process, I connected it to the Internet and updated the installer when asked. I did not install any other third party software.
  4. Done!

Troubleshooting

Here is a list of issues and their resolution I encountered in the past.

Package manager

Ubuntu's maintainer, Canonical, has created its own package manager called Snap to live besides the Debian's APT. Below is a comparison.

FeatureAPTSnap
SourceDebian reposSnapcraft store
Format.deb.snap
SizeSmallLarge
Install methodapt installsnap install
Install location/usr/snap (mounted via loop devices)
IsolationNo (shared system libs)Yes (sandboxed with own libs)
Dependency conflictProbableNo
SecurityCommunityCanonical
SpeedFast install & launchSlower install & launch (due to sandboxing)
DebugEasyHard
CustomizeEasyHard
Latest versionNoYes
Auto updatesNoYes (in background)

To sum up, use APT unless we need sandboxing, auto-updates, or the latest version of a software.

Set up development environment

Here are the steps I take to set up my development environment.

  1. Install LibreOffice.
    sudo apt install libreoffice
    
  2. Install Google Chrome.
    sudo apt install ./google-chrome-stable_current_amd64.deb
    
  3. Install Visual Studio Code and configure zoom level and terminal scrollback limit.
    sudo apt install ./code_x.x.x_amd64.deb
    
  4. Install cURL.
    sudo apt install curl
    
  5. Install Rust.
    curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
    
  6. Install Git and configure identity and SSH keys.
    sudo apt install git
    git config –global user.email <EMAIL>
    ssh-keygen -t ed25519 -C “<COMMENT>”
    eval “$(ssh-agent -s)”
    ssh-add ~/.ssh/id_ed25519
    
  7. Install Zola.
    • Compile from source.
      git clone git@github.com:getzola/zola.git
      cd zola
      cargo install –path . –locked
      
    • Or use snap package manager.
      snap install --edge zola
      
  8. Install Docker.
    sudo apt install docker.io
    
  9. Install FFmpeg.
    sudo apt install ffmpeg
    
  10. Install MuseScore3.
    sudo apt install musescore3
    
  11. Install nvidia-container-toolkit.
    curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
    && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
        sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
        sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
    
    sudo apt update
    sudo apt install -y nvidia-container-toolkit
    sudo systemctl restart docker
    sudo docker run --rm --gpus all nvidia/cuda:12.2.0-base-ubuntu22.04 nvidia-smi # Verify nvidia-container-toolkit installation.
    
  12. Install python3.12-venv.
    sudo apt install python3.12-venv`
    
  13. Install Go.
    1. Download the latest archive from the Go official website.
    2. Extract the files at /user/local.
      sudo tar -C /usr/local -xzf go<MAJOR>.<MINOR>.<PATCH>.linux-amd64.tar.gz
      
    3. Add this to the .bashrc file.
      PATH="$PATH:/usr/local/go/bin"
      
    4. Open a new terminal and verify the installation.
      go version
      
  14. Install pre-commit.
    sudo apt install pre-commit`
    
  15. Install PostgreSQL.
    sudo apt install postgresql
    
  16. Install Vim.
    sudo apt install vim
    
  17. Install python3-venv.
    sudo apt install python3-venv
    
  18. Install graphviz for go pprof visualization.
    sudo apt install graphviz
    
  19. Install protocol buffer compiler and Go plugins.
    sudo apt install protobuf-compiler
    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
    
  20. Install Claude Code and configure it to use a Google Gemini model.
    1. Go to Google AI studio API keys to create a new API key or use an existing one. Copy the API key <GEMINI_API_KEY> for later use.
    2. Decide which Google Gemini model, <GEMINI_MODEL>, we want to use, e.g., gemini-3.1-flash-lite.
    3. Go to the project root directory.
      cd <PROJECT_PATH>
      
    4. Install LiteLLM proxy as a translator between Anthropic's request/response format and Google's.
      curl -fsSL https://raw.githubusercontent.com/BerriAI/litellm/main/scripts/install.sh | sh
      
    5. Run the LiteLLM setup wizard.
      litellm --setup
      
      1. Select Google Gemini as the LLM provider.
      2. Input nothing for the Google Gemini API key as we will configure it via an environment variable later.
      3. Accept the default port number <PORT>.
      4. Accept the default LiteLLM master key <LITELLM_MASTER_KEY>.
      5. Decline starting the proxy and exit.
      6. Now a litellm_config.yaml should exist in the project root directory and contain the LiteLLM master key.
    6. Create a .env with the below content.
      GEMINI_API_KEY="<GEMINI_API_KEY>"
      ANTHROPIC_API_KEY="<LITELLM_MASTER_KEY>"
      ANTHROPIC_BASE_URL="http://localhost:<PORT>"
      ANTHROPIC_MODEL="<GEMINI_MODEL>"
      
    7. Append the below code to the .bashrc so whenever a terminal is opened it scans the directory to find a .env and creates environment variables from the content.
      load_dot_env_file() {
          if [ -f .env ]; then
              set -a
              source .env
              set +a
          fi
      }
      
      if [[ ! "$PROMPT_COMMAND" =~ "load_dot_env_file" ]]; then
          PROMPT_COMMAND="load_dot_env_file; $PROMPT_COMMAND"
          echo "added .env loading function to prompt command"
      fi
      
    8. Update the litellm_config.yaml to the below content.
      model_list:
        - model_name: <GEMINI_MODEL>
          litellm_params:
            model: gemini/<GEMINI_MODEL>
            api_key: os.environ/GEMINI_API_KEY
      
    9. Run the LiteLLM server.
      litellm --config litellm_config.yaml
      
    10. Open a new terminal and install Claude Code CLI.
      curl -fsSL https://claude.ai/install.sh | bash
      
    11. Add the below code to the .bashrc so we can run claude at any location.
      export PATH="/home/apogee/.local/bin:$PATH"
      
    12. Run Claude Code CLI to test it out.
      claude
      
    13. (Optional) If using VSCode Claude Code extension, add the below content to the settings.json.
      "claudeCode.disableLoginPrompt": true,
      "claudeCode.environmentVariables": [
          {
              "name": "ANTHROPIC_API_KEY",
              "value": "<LITELLM_MASTER_KEY>"
          },
          {
              "name": "ANTHROPIC_BASE_URL",
              "value": "http://localhost:<PORT>"
          },
          {
              "name": "ANTHROPIC_MODEL",
              "value": "<GEMINI_MODEL>"
          }
      ]
      
  21. Install SQLite.
    sudo apt install sqlite3
    

References

←Previous Next→