โ† Back to DevBytes

Linux Mint Server Setup: From Installation to Production

Introduction: Linux Mint as a Server OS

Linux Mint is widely known as a user-friendly desktop distribution, but it also makes an excellent server platform. Built on Ubuntu's long-term support (LTS) repositories, Linux Mint inherits rock-solid stability, a vast package ecosystem, and predictable update cycles. For developers and small teams who want a familiar environment from desktop to server, Linux Mint Server Editionโ€”or more commonly, a minimal installation of Linux Mint configured as a headless serverโ€”offers a practical middle ground between Debian's austerity and Ubuntu Server's cloud-centric design.

This tutorial walks you through the complete journey: from bare-metal ISO installation to a secure, production-ready server running web applications, databases, and automated services. Every step includes practical code you can copy and adapt to your own environment.

What Is a Linux Mint Server?

๐Ÿš€ Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

A Linux Mint server is simply a Linux Mint installation stripped of its desktop environment and repurposed for server workloads. There is no separate "Server Edition" ISOโ€”instead, you install the base system, then configure it to run headless services such as:

Because Linux Mint tracks Ubuntu's LTS base (currently 24.04 Noble Numbat for Mint 22.x), you get five years of security updates without the need for rolling-release gymnastics. This makes it viable for production environments where stability trumps novelty.

Why Choose Linux Mint for a Server?

Several practical reasons make Linux Mint a compelling server choice:

Step 1 โ€” Download and Prepare Installation Media

Download the Linux Mint ISO from the official site. Choose the 64-bit Cinnamon edition for familiarity, or the Xfce edition if you want a lighter fallback GUI. For a true headless server, you will later disable the graphical target.

Write the ISO to a USB drive using dd or a tool like Balena Etcher:

# Identify your USB device (e.g., /dev/sdb)
lsblk

# Write the ISO (replace paths accordingly)
sudo dd if=linuxmint-22-cinnamon-64bit.iso of=/dev/sdb bs=4M status=progress oflag=sync

Step 2 โ€” Base System Installation

Boot from the USB drive. When the installer launches, choose the minimal installation approach:

After the installation completes and the system reboots, log in at the console. Your server is now running a full desktop environment, but we will convert it to a headless server shortly.

Step 3 โ€” Convert to Headless Mode

To save resources and align with server conventions, disable the graphical display manager and boot into multi-user console mode:

# Stop the display manager
sudo systemctl stop lightdm

# Disable it from starting on boot
sudo systemctl disable lightdm

# Set the default systemd target to multi-user (no GUI)
sudo systemctl set-default multi-user.target

# Reboot to apply changes
sudo reboot

After reboot, you will be greeted by a plain text console. Your server is now headless and conserves roughly 300โ€“500 MB of RAM compared to the desktop session.

Step 4 โ€” Network Configuration

Configure a static IP address so your server is always reachable at a predictable address. On Linux Mint (which uses NetworkManager by default even in multi-user mode), you can use nmcli or edit the Netplan configuration if you switched networking stacks.

Option A: Using NetworkManager (nmcli)

# List connections
nmcli con show

# Create or modify a static connection (adjust interface name, IP, gateway)
sudo nmcli con add con-name "static-eth0" ifname eth0 type ethernet \
  ipv4.method manual ipv4.addresses 192.168.1.100/24 \
  ipv4.gateway 192.168.1.1 ipv4.dns "8.8.8.8,1.1.1.1"

Option B: Using Netplan (if installed)

# Edit the Netplan YAML file
sudo nano /etc/netplan/01-netcfg.yaml
network:
  version: 2
  ethernets:
    enp0s3:
      addresses:
        - 192.168.1.100/24
      gateway4: 192.168.1.1
      nameservers:
        addresses: [8.8.8.8, 1.1.1.1]
# Apply the configuration
sudo netplan apply

Verify connectivity:

ip a show
ping -c 4 1.1.1.1

Step 5 โ€” System Update and Essential Packages

Immediately update the package index and install foundational server tools:

# Update package lists and upgrade existing packages
sudo apt update && sudo apt upgrade -y

# Install essential server utilities
sudo apt install -y curl wget git build-essential htop \
  unzip zip ufw fail2ban tmux vim nano \
  software-properties-common apt-transport-https \
  ca-certificates gnupg lsb-release

These packages provide a comfortable administration environment and lay the groundwork for installing third-party software securely via HTTPS repositories.

Step 6 โ€” Create a Dedicated Administrative User

Never operate as root. Create a dedicated admin user with sudo privileges:

# Create a new user (replace 'opsadmin' with your preferred name)
sudo adduser opsadmin

# Add to sudo group
sudo usermod -aG sudo opsadmin

# Optionally add SSH keys for this user
sudo mkdir -p /home/opsadmin/.ssh
sudo chmod 700 /home/opsadmin/.ssh
sudo touch /home/opsadmin/.ssh/authorized_keys
sudo chmod 600 /home/opsadmin/.ssh/authorized_keys
sudo chown -R opsadmin:opsadmin /home/opsadmin/.ssh

Step 7 โ€” SSH Hardening

Secure Shell is your primary management channel. Harden it before exposing the server to any network:

# Edit the SSH daemon configuration
sudo nano /etc/ssh/sshd_config

Apply these changes:

# Disable root login over SSH
PermitRootLogin no

# Disable password authentication (use keys only)
PasswordAuthentication no

# Disable empty passwords
PermitEmptyPasswords no

# Use a non-standard port (optional, reduces log noise)
Port 22022

# Limit authentication attempts
MaxAuthTries 3

# Disable X11 forwarding (not needed on a server)
X11Forwarding no

# Allow only your admin user
AllowUsers opsadmin

Reload SSH to apply changes:

sudo systemctl reload sshd

Important: Before disabling password authentication, ensure you have copied your SSH public key to the server and tested key-based login successfully. Locking yourself out is a common pitfall.

Step 8 โ€” Configure the Firewall with UFW

UFW (Uncomplicated Firewall) provides a human-friendly interface to iptables. Enable it with a strict default-deny policy:

# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow SSH (adjust port if you changed it)
sudo ufw allow 22022/tcp

# Enable the firewall
sudo ufw enable

# Verify status
sudo ufw status verbose

Later, you will open additional ports (80, 443, database ports) as services are installed.

Step 9 โ€” Install and Configure Fail2ban

Fail2ban monitors logs and temporarily bans IPs that exhibit malicious behaviorโ€”brute-force SSH attempts, HTTP probing, etc.

# Enable and start fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

# Check status of the SSH jail
sudo fail2ban-client status sshd

Customize the SSH jail to match your non-standard port:

# Create a local override file
sudo nano /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 22022
maxretry = 3
bantime = 3600
findtime = 600
sudo systemctl restart fail2ban

Step 10 โ€” Automatic Security Updates

Enable unattended upgrades so critical security patches apply without manual intervention:

sudo apt install -y unattended-upgrades

# Enable automatic updates
sudo dpkg-reconfigure --priority=low unattended-upgrades

Fine-tune the behavior by editing the configuration:

sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

Ensure the Unattended-Upgrade::Allowed-Origins block includes security updates and optionally stable updates:

Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
    "${distro_id}ESM:${distro_codename}";
};

Step 11 โ€” Web Server Setup (Nginx + PHP-FPM)

Install Nginx as your reverse proxy and application server, along with PHP-FPM for dynamic content:

# Install Nginx and PHP-FPM with common extensions
sudo apt install -y nginx php-fpm php-mysql php-xml \
  php-mbstring php-curl php-zip php-gd php-bcmath \
  php-json php-intl php-imagick

Configure a sample virtual host

sudo nano /etc/nginx/sites-available/app.example.com
server {
    listen 80;
    server_name app.example.com;
    root /var/www/app.example.com/public;
    index index.php index.html;

    access_log /var/log/nginx/app_access.log;
    error_log /var/log/nginx/app_error.log;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }
}
# Enable the site
sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/

# Test configuration and reload
sudo nginx -t
sudo systemctl reload nginx

Open the HTTP port in the firewall:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Step 12 โ€” SSL/TLS with Let's Encrypt (Certbot)

Secure your web traffic with free, automated TLS certificates:

# Install Certbot
sudo apt install -y certbot python3-certbot-nginx

# Obtain and auto-configure an SSL certificate
sudo certbot --nginx -d app.example.com

# Test auto-renewal
sudo certbot renew --dry-run

Certbot modifies your Nginx configuration to redirect HTTP to HTTPS and enables modern TLS settings. A systemd timer handles renewal automatically.

Step 13 โ€” Database Engine (MariaDB)

Install MariaDB, a drop-in replacement for MySQL with active development and better licensing:

sudo apt install -y mariadb-server mariadb-client

# Secure the installation
sudo mysql_secure_installation

During mysql_secure_installation, answer the prompts as follows:

Create an application-specific database and user:

sudo mysql -u root -p
CREATE DATABASE app_production CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'strong_password_here';
GRANT ALL PRIVILEGES ON app_production.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Step 14 โ€” Node.js Runtime (via NodeSource)

For JavaScript-based applications, install Node.js from the official NodeSource repository to get a current LTS version:

# Add NodeSource repository (replace 20.x with desired LTS)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -

# Install Node.js
sudo apt install -y nodejs

# Verify installation
node --version
npm --version

Install PM2, a production-grade process manager for Node.js applications:

sudo npm install -g pm2

# Start a sample application
pm2 start /var/www/app.example.com/server.js --name "app-backend"

# Save the process list for resurrection on reboot
pm2 save

# Enable PM2 to start on boot
pm2 startup systemd
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u opsadmin --hp /home/opsadmin

Step 15 โ€” Docker and Containerization

Docker allows you to package applications with their dependencies into portable containers. Install Docker Engine from the official repository:

# Add Docker's GPG key and repository
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo "deb [arch=$(dpkg --print-architecture) \
  signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Install Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin

# Add your admin user to the docker group
sudo usermod -aG docker opsadmin

# Enable and start Docker
sudo systemctl enable docker
sudo systemctl start docker

Verify the installation:

docker run --rm hello-world

Step 16 โ€” Monitoring with Netdata

Real-time monitoring helps you detect anomalies before they become outages. Netdata provides a lightweight, out-of-the-box monitoring dashboard:

# Install Netdata via the official kickstart script
bash <(curl -Ss https://my-netdata.io/kickstart.sh) \
  --stable-channel --disable-telemetry

# Netdata listens on localhost:19999 by default
# To access it remotely, set up an Nginx reverse proxy or SSH tunnel

Configure an Nginx reverse proxy for the Netdata dashboard (behind authentication):

sudo nano /etc/nginx/sites-available/netdata.example.com
server {
    listen 80;
    server_name netdata.example.com;
    
    auth_basic "Netdata Dashboard";
    auth_basic_user_file /etc/nginx/.htpasswd;

    location / {
        proxy_pass http://127.0.0.1:19999;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
# Create HTTP basic auth credentials
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd monitor_user

# Enable site and reload Nginx
sudo ln -s /etc/nginx/sites-available/netdata.example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

# Obtain SSL certificate for the monitoring subdomain
sudo certbot --nginx -d netdata.example.com

Step 17 โ€” Automated Backups with BorgBackup

Production servers require automated, deduplicated backups. BorgBackup is efficient and encryption-capable:

sudo apt install -y borgbackup

# Initialize a Borg repository (local or remote)
borg init --encryption=repokey /backup-repo

# Create a backup script
sudo nano /usr/local/bin/daily-backup.sh
#!/bin/bash
set -e

export BORG_PASSPHRASE="your-strong-passphrase"

borg create --stats --compression lz4 \
  /backup-repo::'{hostname}-{now:%Y-%m-%d}' \
  /etc \
  /var/www \
  /var/lib/mysql \
  /home/opsadmin

borg prune --keep-daily=7 --keep-weekly=4 --keep-monthly=6 /backup-repo
sudo chmod +x /usr/local/bin/daily-backup.sh

# Schedule via cron (runs daily at 2 AM)
echo "0 2 * * * root /usr/local/bin/daily-backup.sh >> /var/log/backup.log 2>&1" | \
  sudo tee /etc/cron.d/borg-backup

Step 18 โ€” Log Management with Journald and Logrotate

Systemd's journal collects all service logs. Ensure persistent storage and configure rotation:

# Enable persistent journal storage
sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald

# Configure log retention (edit /etc/systemd/journald.conf)
sudo nano /etc/systemd/journald.conf
[Journal]
Storage=persistent
SystemMaxUse=500M
MaxRetentionSec=30day

For application logs, configure logrotate:

sudo nano /etc/logrotate.d/custom-apps
/var/log/nginx/app_*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 www-data www-data
    sharedscripts
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
    endscript
}

Step 19 โ€” Kernel and System Hardening

Apply additional hardening via sysctl parameters:

sudo nano /etc/sysctl.d/99-hardening.conf
# IP spoofing protection
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Disable IP source routing
net.ipv4.conf.all.accept_source_route = 0

# Disable ICMP redirect acceptance
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

# Enable SYN flood protection
net.ipv4.tcp_syncookies = 1

# Disable IPv6 if not needed
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
# Apply immediately
sudo sysctl -p /etc/sysctl.d/99-hardening.conf

Step 20 โ€” Production Deployment Checklist

Before declaring your server production-ready, run through this verification checklist:

Best Practices Summary

Throughout this tutorial, several recurring themes emerge. Keep these principles in mind as your server evolves:

Conclusion

You have now taken a stock Linux Mint installation from a desktop-oriented system to a hardened, headless production server capable of serving web applications, running containerized workloads, and surviving the harsh realities of the public internet. The journey involved stripping away unnecessary components, layering on security controls, installing modern runtime environments, and establishing automated monitoring and backup regimens.

Linux Mint's Ubuntu LTS foundation gives you enterprise-grade stability while its desktop heritage provides a comfortable fallback if you ever need to plug in a monitor for emergency troubleshooting. By following this guide, you have built a server that is secure, maintainable, and ready to handle real traffic. The next step is to codify this configuration into infrastructure-as-code using tools like Ansible, Terraform, or a simple shell provisioning scriptโ€”so your next deployment takes minutes, not hours.

๐Ÿš€ Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started โ€” $23.99/mo
โ† Back to all articles