Mono is an open source implementation of Microsoft‘s .NET Framework. It allows developers to build cross-platform .NET applications that can run on Linux, Windows, macOS, and more. In this comprehensive guide, we will cover how to install Mono on Linux Mint and configure it for building .NET applications.
Prerequisites
Before installing Mono, ensure your system meets the following requirements:
- Linux Mint 20 or higher
- An internet connection for downloading packages
It‘s also recommended to have basic knowledge of working with a Linux terminal.
Installing Mono
There are a few ways to install Mono on Linux Mint. We will cover the main methods below.
Install with APT
The easiest way to install Mono is via the apt package manager, as Mono packages are available in the standard Mint repositories.
First, update your package index:
sudo apt update
Then install the Mono complete package:
sudo apt install mono-complete
This will install the mono-devel package along with all Mono libraries and tools like the C# compiler and the mod-mono web server.
I‘d recommend this method for most use cases, as the apt packages contain everything you need to start developing .NET apps out-of-the-box.
Install Manually via Repositories
You can also install Mono by adding the upstream Mono project repository and installing from there. This allows you to stay on the bleeding edge of Mono releases.
First, add the GPG signing key:
wget -qO - https://download.mono-project.com/repo/xamarin.gpg | sudo apt-key add -
Next, add the Mono repository to your sources list:
echo "deb https://download.mono-project.com/repo/ubuntu stable-focal main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list
Update your package index:
sudo apt update
Finally, install mono-complete:
sudo apt install mono-complete
Now you‘ll have the latest stable Mono platform installed.
This is useful if you want early previews of new Mono features before they hit the main package archives. But bleeding edge builds may contain bugs.
Compiling from Source
You can also compile and install Mono from source code. This allows you to customize your build but takes more time and effort.
First install some compiler dependencies:
sudo apt install build-essential autoconf libtool pkg-config
Next download and extract the Mono source tarball:
wget https://download.mono-project.com/sources/mono/mono-6.12.0.107.tar.xz
tar xvf mono-6.12.0.107.tar.xz
Enter the extracted directory and configure the build:
cd mono-6.12.0.107
./configure
Now compile everything:
make
And finally install Mono system-wide:
sudo make install
Compiling from source allows you to tweak configuration like disabling features or targeting newer architectures. But it takes much longer to setup.
Stick to the apt or repository methods unless you specifically need a custom Mono build.
Using the Mono Runtime
After installing Mono, you can begin running .NET applications. You‘ll generally use the mono command to execute .NET executables and assemblies.
For example, try running the Mono sample QuickStart app:
mono /usr/lib/mono/4.5/QuickStart.exe
You should see the graphical tutorial launch. This confirms your Mono runtime works correctly!
Browse the /usr/lib/mono/ directories to find other sample .NET applications included in the Mono distribution.
Performance Considerations
Mono features two distinct runtime models – a just-in-time (JIT) compiler similar to .NET on Windows, and an ahead-of-time (AOT) native compiler for Linux.
AOT vs JIT
The JIT model compiles .NET IL bytecode lazily on first run. This results in slower cold startups but faster warm optimizable code.
Meanwhile AOT compiles an entire application to native machine code on installation. So apps start very fast but lose some peak performance vs optimized JIT code.
For web apps and services, I‘d recommend AOT to reduce user-visible delays on first requests. For compute workloads, profile with both models.
Development vs Production
During development, using -debug with mcs and launching apps with --debug enables profiler tools to help locate bottlenecks in code.
But disable debugging in production AOT-compiled deployments for faster performance.
Garbage Collection
Mono uses a generational garbage collector by default. This is relatively efficient for short-lived allocations common in web code.
For long-running batch processes, consider using -gc=sgen during AOT compilation to enable the SGen collector for reduced GC overhead.
Tuning these flags requires benchmarking – but can yield big perf wins!
Compiling C# Code
The main C# compiler shipped with Mono is mcs. This turns C# into .NET assemblies executable by the Mono runtime.
Here‘s a sample "Hello World":
using System;
public class Hello
{
public static void Main()
{
Console.WriteLine("Hello Mono World!");
}
}
Compile with:
mcs hello.cs
And execute the resulting binary:
mono hello.exe
You will see "Hello Mono World!" output.
mcs supports the full C# language specification along with referencing NuGet packages from remote repositories. This enables building complex cross-platform apps.
During development, pass -debug to mcs enable debugging capabilities like breakpoints. But compile release builds without this for better security and performance.
Configuring the Mono Environment
There are some useful configurations when working with Mono:
Using NuGet Packages
NuGet powers package management for .NET libraries – similar to PIP in Python. This lets you reference common functionality in projects.
For example, to use the Newtonsoft JSON parser:
mono nuget.exe install Newtonsoft.Json
Now using Newtonsoft.Json will work in C# code.
NuGet caches packages to ~/.nuget by default. To automatically restore on each build:
mono nuget.exe config -set globalPackagesFolder=~/.nuget
mono nuget.exe config -set dependencyVersion highestPatch
This saves time hunting down dependencies manually!
Integrating with a C# IDE
For serious C# development on Linux, I‘d highly recommend using an IDE like:
-
Visual Studio Code: Excellent free option with great Mono support via the C# extension
-
JetBrains Rider: Paid but very full-featured for Linux .NET development
These provide auto-complete, debugging, profiling, and more. Much easier than coding directly in a terminal!
For VS Code, ensure the C# extension is installed for Mono support.
In Rider, enable Mono by going to Preferences > Build, Execution, Deployment > Mono
An IDE speeds up the edit, compile, debug loop.
Targeting Mono and .NET Frameworks
By default Mono targets .NET Framework v4.5 for maximum backwards compatibility.
But for newer language features or hosting on modern Windows servers, target a newer framework:
mcs -sdk:5.0 MyApp.cs
Or configure globally with:
export FRAMEWORK_VERSION=5.0
Just beware dropping too low or high breaks runtime support – test thoroughly!
I‘d currently recommend targeting .NET 5 which hits the sweet spot of new features and compatibility.
Debugging Mono Applications
Debugging is infinitely easier using an IDE mentioned previously.
But it is also possible directly from terminal. First compile with debugging symbols:
mcs -debug MyApp.cs
Then launch to automatically enter debug mode:
mono --debug MyApp.exe
This provides an interactive prompt where you can:
- Set breakpoints with
break FileName.cs:12 - Print variables using
print myVariable - Step through code line-by-line using
next,step,finish
So debugging without an IDE in a pinch is possible!
Running ASP.NET Web Applications
A very common use of Mono is building web APIs and sites with C# and ASP.NET.
The mod_mono Apache module enables executing .NET web apps:
sudo apt install apache2 libapache2-mod-mono
Enable mod_mono:
sudo a2enmod mono
And restart Apache:
sudo systemctl restart apache2
Your web root will be /var/www/html/. Place an ASP.NET app here like:
MyWebApp/web.config
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
</configuration>
This will run server-side C# code alongside static assets!
Integrating ASP.NET Core
Newer ASP.NET Core apps run via Kestrel instead of mod_mono. You can proxy these through nginx:
sudo apt install nginx
/etc/nginx/sites-enabled/proxy.conf:
server {
location / {
proxy_pass http://localhost:5000;
}
location /api/ {
rewrite ^/api/?(.*) /$1 break;
proxy_pass http://localhost:5001;
}
}
This routes ASP.NET on port 5000 and ASP.NET Core on 5001.
Integrating NodeJS
Mono often works alongside other backends like NodeJS:
Startup.cs
public void ConfigureServices(IServiceCollection services) {
services.AddControllers();
services.AddSpaStaticFiles(options => {
options.RootPath = "ClientApp/dist";
});
}
public void Configure(IApplicationBuilder app) {
app.UseRouting();
app.UseEndpoints(routes => {
routes.MapControllers();
});
app.UseSpaStaticFiles();
app.UseSpa(spa => {
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
});
}
This bridges NodeJS frontend code running on port 4200 with C# APIs!
ASP.NET interop enables building advanced modern web apps.
Securing Mono
Since Mono executes arbitrary C# code on Linux, it presents a potential attack vector like any runtime.
Here are some tips for using Mono securely:
-
Drop privileges via
setcap cap_net_bind_service=+ep /usr/bin/monoto limit systemic impacts -
Use AppArmor, SELinux mandatory access controls to restrict file/network access
-
Follow C# secure coding best practices – validate inputs, sanitize outputs, etc
-
Use NuGet packages only from trusted sources
-
Keep Mono up-to-date applying all stable patches
-
Static analyze .NET code for vulnerabilities before deploying
Following basic secure development practices for C# and configuring OS-level sandboxing via apparmor/SELinux profiles mitigates most Mono risk.
But beware malicious .NET code could still impact the system – tread carefully!
Troubleshooting Mono
If running into Mono issues, some things to try:
-
Check version with
mono --versionif seeing odd runtime errors -
Inspect logs at
/var/log/mono/for crash stack traces -
Retry NuGet package restores manually via
mono nuget.exe restore -
Confirm Mono finds config at
/etc/mono/4.5/machine.config -
Use
strace mono MyApp.exeto help diagnose failures -
Ensure compiled assemblies target a Mono-compatible framework version
Also reference the extensive Mono troubleshooting documentation which is quite helpful.
And ask the knowledgeable Mono community support channels if problems persist!
Updating Mono
New stable Mono releases ship every couple months with fixes and features.
To update existing installs – first grab latest packages:
sudo apt update
Check for any available upgrades:
apt list --upgradable
If you see mono-complete listed, install updates:
sudo apt upgrade
This fetches the latest builds from repositories.
Systems installed via the Mono project repository receive updates automatically.
Review release notes before applying production upgrades – although these are generally safe.
Uninstalling Mono
To completely remove Mono:
sudo apt purge mono-complete
Additionally delete unused dependencies:
sudo apt autoremove
And consider nuking the cached ~/.nuget/ folder if not needed.
Once uninstalled, Mono .NET applications will fail to launch without the runtime.
The Future of Mono
Mono has come a long way from its early days led by Xamarin and the open source community.
It now provides production-grade support for running cross-platform C# applications across desktop, mobile, web, and cloud environments by efficiently emulating .NET Framework APIs.
Recently Microsoft adopted stewardship over Mono as it aligned with their vision for enabling .NET adoption globally on non-Windows platforms.
Microsoft has contributed heavily to Mono allowing it to support new .NET runtimes like .NET 5 and .NET 6 rather than just chasing .NET Framework compatibility.
.NET Core & C# 8+
As .NET itself continues becoming more modular and cross-platform, expect Mono to follow a similar trajectory:
We‘ll likely see Mono frameworks like System.Json replaced with referencing System.Text.Json from .NET Core instead for example.
And increased focus on only implementing modern standardized APIs rather than .NET Framework quirks.
C# 8 and 9 language features will be compiled ahead-of-time as the AOT compiler catches up.
This increases cross-OS portability as more of the base platform standardizes.
WebAssembly & Mobile
We could also see Mono compile C# to WebAssembly allowing .NET code to run in browsers rather than just on servers. Prototypes of this already exist today!
And improvements towards Xamarin‘s vision of C# code reuse across Android/iOS mobile development.
Microsoft seems committed to building up .NET as the premiere enterprise application development ecosystem.
Mono serves as the gateway towards running these workloads efficiently on massive existing Linux deployments.
The future looks bright as Microsoft and the Mono community usher .NET into its next generation!
Conclusion
Mono enables building and running cross-platform C# applications on Linux, macOS, and more.
It provides industrial-grade support for .NET Framework APIs via an efficient AOT-compiled runtime for desktop, web, mobile, gaming, and IoT use cases.
We covered multiple install methods, compiling C#, leveraging NuGet packages, debugging tricks, ASP.NET integration examples, security considerations, and predictions for Mono‘s continued evolution.
Microsoft‘s backing solidifies Mono‘s position as the .NET runtime for non-Windows platforms going forward alongside .NET Core‘s convergence.
Let us know if you have any other questions!


