Setting Up Ubuntu Server: A Quick Guide! 🌟

Ubuntu_2026.md Public

Dive into the exciting world of Ubuntu Server setup with this concise guide! 🚀 From installing essential tools like 'tree' and 'Oh My Zsh' to configuring user permissions and security measures, this walkthrough has you covered. Get ready to unleash the full potential of your server! 💻✨

Ubuntu Server

Set up

Using Ubuntu 24.04 LTS which already has python3.12

1. install tree

sudo apt update
sudo apt upgrade -y
sudo apt-get install tree
sudo apt install python3.12-venv

2. Install Oh My Zsh

sudo apt install zsh -y
sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

modify .zshrc

  • sudo nano ~/.zshrc
  • make changes:
# Nick added
alias python=python3.12
alias ss_status="sudo systemctl status"
alias ss_start="sudo systemctl start"
alias ss_stop="sudo systemctl stop"

echo ".zshrc loaded ✅"

3. Node.js

global for nick and all users

curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs

Claude Code

  • consider
  • I did this in the nws-kv23 server 2026-02-16, if this still works then continue using it.
1. make server level .npm
mkdir ~/.npm-global
npm config set prefix '~/.npm-global'
echo 'export PATH=$HOME/.npm-global/bin:$PATH' >> ~/.zshrc
source ~/.zshrc
2. Install claude

npm install -g @anthropic-ai/claude-code

4. Install GitHub

  1. from terminal: ssh-keygen -t ed25519 -C "nrodrig1@gmail.com"
  2. start ssh-agent: eval "$(ssh-agent -s)"
  3. create or modify ~/.ssh/config file
  • nano ~/.ssh/config
Host github.com
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519
  1. place your ssh key in the Github page: https://github.com/settings/keys
  • copy SSH public key from terminal command: cat ~/.ssh/id_ed25519.pub

5. Create folder structure

mkdir applications
mkdir databases
mkdir environments
mkdir project_resources
mkdir _config_files
mkdir logs

6. Setting Up limited_user for Application Deployment

A least-privilege user for running Python and Node.js applications via systemd services.

1. Create the User

sudo useradd --system --create-home --home-dir /home/limited_user --shell /usr/sbin/nologin limited_user

This creates a system user with a home directory at /home/limited_user, no login shell (cannot SSH or interactively log in), and no sudo group membership.

2. Give nick access to home/limited_user

This sets 770 permissions so the owner (limited_user) gets full access and the group gets read/execute.

sudo chmod 770 /home/limited_user
sudo chown limited_user:limited_user /home/limited_user
sudo usermod -aG limited_user nick

This sets the default ACL so any new files and directories created under /home/limited_user will grant the group read, write, and execute permissions.

sudo chmod g+s /home/limited_user
sudo apt install acl
sudo setfacl -d -m g::rwx /home/limited_user
If needed: recursive ownership

Give the limited_user ownership and make all contents owned by limited_user

sudo chown -R limited_user:limited_user /home/limited_user/
sudo chmod -R u=rwX,g=rwX /home/limited_user/

3. Set Up Application Directories

sudo -u limited_user mkdir /home/limited_user/applications
sudo -u limited_user mkdir /home/limited_user/databases
sudo -u limited_user mkdir /home/limited_user/environments
sudo -u limited_user mkdir /home/limited_user/project_resources
sudo -u limited_user mkdir /home/limited_user/_config_files
sudo -u limited_user mkdir /home/limited_user/logs

4. Install / build npm

sudo -u limited_user npm install
sudo -u limited_user npm run build

7. Clone TheServerManager

git clone git@github.com:costa-rica/TheServerManager.git

8. Set sudoer permissions

  1. create the nick-systemctl.csv file
  2. add the /home/nick/update-nick-systemctl.sh file
  3. run the update-nick-systemctl.sh file by typing to terminal: /home/nick/update-nick-systemctl.sh
  4. make file executable: chmod +x /home/nick/update-nick-systemctl.sh

Common Ubuntu commands

# See content privileges
ls -l

# see user groups
groups [username]



service file commands

sudo systemctl daemon-reload
sudo systemctl enable personalweb03-api
sudo systemctl start personalweb03-api
sudo systemctl status personalweb03-api

# see logs
sudo journalctl -u personalweb03-api
sudo journalctl -u newsnexus10api.service -f

# Stop the timer (prevents future runs)
sudo systemctl stop personalweb03-services.timer

# Disable it (won't start on boot)
sudo systemctl disable personalweb03-services.timer

# Verify it's stopped
sudo systemctl list-timers

# reset failed (i.e. due to `StartLimitIntervalSec=1d`)
sudo systemctl reset-failed newsnexusrequesternewsapi01.service

Permissions

Example:

➜  NewsNexus10API git:(dev_02_logging) ls -ld /home/nick/logs
drwxr-xr-x 2 nick nick 4096 Dec 22 23:58 /home/nick/logs

Breakdown:

  • drwxr-xr-x 2 nick nick breaks down as follows:

    • d → directory
    • rwx (owner: nick) → read, write, enter directory
    • r-x (group: nick) → read, enter directory, no write
    • r-x (others) → read, enter directory, no write
  • 2 = number of hard links (directory + parent reference).

  • Ownership:

    • User: nick
    • Group: nick

Set off .timer files

1.

sudo systemctl daemon-reload
sudo systemctl enable --now personalweb03-services.timer

check status

systemctl list-timers

Security

  • see the /Users/nick/Documents/CheckLogsSuspiciousActivity project
    • use codex to place syslog and auth.log files and just have it scan them.

Fail2ban

Install

sudo apt update
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban
sudo fail2ban-client status
After editing jail files
sudo systemctl restart fail2ban
sudo fail2ban-client status

SSH Brute-Force Protection (sshd jail)

  1. Create file:
sudo nano /etc/fail2ban/jail.d/sshd.local
  1. Paste:
[sshd]
enabled = true
maxretry = 8
findtime = 30m
bantime = 2h
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 1w
  1. Apply and verify:
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
sudo fail2ban-client get sshd maxretry
sudo fail2ban-client get sshd findtime
sudo fail2ban-client get sshd bantime

Nginx 404 Burst Protection

  1. Create file:
sudo nano /etc/fail2ban/jail.local
  1. Paste:
[nginx-404]
enabled  = true
filter   = nginx-404
logpath  = /var/log/nginx/access.log
backend = polling
maxretry = 20
findtime = 2m
bantime  = 1h
  1. Apply and verify:
sudo fail2ban-client -t
sudo systemctl restart fail2ban
sudo fail2ban-client status nginx-404
  1. Useful ops commands:
# See banned IPs for this jail
sudo fail2ban-client status nginx-404

# Unban one IP if needed
sudo fail2ban-client set nginx-404 unbanip <IP>

Nginx Rate Limiting

Edit the /etc/nginx/nginx.conf file. using sudo nano /etc/nginx/nginx.conf.

http {
	##
	# Nick added for rate limiting
	##
	# In http block
	limit_req_zone $binary_remote_addr zone=general:10m rate=2r/s;
	limit_req_zone $binary_remote_addr zone=strict:10m rate=1r/s;

	# In server block - for most content
	limit_req zone=general burst=20 nodelay;
	##
	# END Nick added for rate limiting
	##

Restart nginx: sudo systemctl restart nginx

UFW

  • allow from sudo ufw allow from 69.207.163.8 to any port 22

VMWare Cloning VM

Step 1: copy vmdk and vmx files to new folder with new VM name

  • original VM should be turned off
  • copy vmdk and vmx files to new folder with new VM name

Step 2: ☝️ [After copy is finished] turn on old VM

  • after finished copy turn ON the old VM
    • This will help because when you get back to the Virtual Machines page / list you'll see two VMs with the same name

Step 3: register the cloned VM

  • From datastore browser navigate to the new VM folder and right click on .vmx file and select "Register VM"
  • From the Virtual Machines page / list rename new VM (which will be the one with the same name but turned off)
  • Turn on the new VM
  • rename the new VM from VMWare
  • hostname from inside terminal of new machine sudo hostnamectl set-hostname <new_hostname>

Using app_runner in nick group

1. create user

  • create group: getent group nick
  • add user to group with no login ability, no home dir:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin -G nick app_runner

2. set permissions

  • Set dir to group rwx and recursivly:
sudo chown -R nick:nick /home/nick/project_resources
sudo chmod -R g+w /home/nick/project_resources
sudo find /home/nick/project_resources -type d -exec chmod g+s {} \;

Key Concepts

  • deleting replacing database causes the permissions to be reset. To change permissions back to group rwx:sudo chmod -R ug+rwX /home/nick/databases
  • Execute (x) on directories: Required to traverse (enter) a directory
  • Read (r) on directories: Required to list directory contents
  • Write (w) on directories: Required to create/delete files in the directory
  • Capital X in chmod: Applies execute only to directories and files already executable

GoAccess

install

sudo apt update
sudo apt install goaccess

create report

  • last 24 hours or whatever is in the log file
sudo goaccess /var/log/nginx/access.log \
  --log-format=COMBINED \
  --date-spec=hr \
  --time-format=%H:%M:%S \
  --date-format=%d/%b/%Y \
  --output=/home/nick/access_maestro06_20251222.json

VMWare

Reverser Proxy Server:

  • CPU: 1
  • Memory: 2GB
  • Hard Disk: 40GM

VM Options > Configuration Parameters to add:

  • disk.EnableUUID: True