Friday, 29 November, 2024

Migrating to Umbraco 13 .NET 8 on Linux Ubuntu

Notes from a recent migration of Umbraco 10 to 13, to new hosting with .NET 8 on Linux Ubuntu.

Migrating to Umbraco 13 .NET 8 on Linux Ubuntu

Recently, I decided it was time to upgrade justaguycoding.com to a modern stack, moving from Umbraco 10 to Umbraco 13 and .NET 8. This upgrade also gave me the opportunity to migrate from my previous hosting provider, InterServer, whose uptime was less than ideal, to a DigitalOcean droplet running Ubuntu 22.04 LTS.

Here are my notes on the migration and how it unfolded.

Why Move to Linux Hosting?

Hosting Umbraco on Linux has been a option for an while and is a good choice for smaller projects. As a rule Linux tends to be cheaper than Windows ASP.NET hosting. I chose DigitalOcean because I love their service, there Linux droplets provide a robust hosting environment great uptime.

I chose to run on Ubuntu 22.04 LTS for its ensured stability, as LTS (Long Term Support) versions receive updates for years. I initially experimented with Ubuntu 23.10 but hit roadblocks, such as the lack of support for SQL Server, which nudged me back to 22.04.

One issue you may have is file naming. Windows is relaxed about filename casing; Linux is not. Websites developed on Windows may have filenames called one things and code paths and links in a different case. These will break on Linux.

Migrating the Database: From MSSQL to SQLite

The first major hurdle was migrating the database. My existing setup used MSSQL, which isn’t natively supported on Linux without installing the Linux version of SQL Server. However, SQL Server didn’t install properly on Ubuntu 23.10 due to a lack of official support. So, I switched to SQLite, a lightweight and fully supported alternative for Umbraco. If you remember SQL Compact Edition it's very similar to that. It's free, open-source, very reliable and file based.

Database Migration Challenges

Migrating from MSSQL to SQLite was not straightforward. Tools like SQL Server Compact Toolbox by Erik Ejlskov Jensen were helpful but couldn’t fully convert my database due to database engine inconsistencies. I ultimately resorted to uSync, an Umbraco configuration and data synchronisation tool by Kevin Jump, to export the content and import it into a fresh SQLite database.

The Upgrade Path: Incremental Steps to Umbraco 13

Upgrading to Umbraco 13 was a step-by-step process:

  1. Upgrade the project to the next Umbraco version.
  2. Resolve any breaking changes in the codebase.
  3. Run Umbraco’s built-in database migration tool.
  4. Repeat until reaching version 13.

By taking small, incremental steps, I avoided being overwhelmed by compatibility issues.

You can read up on the breaking changes between versions here: https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific

The issues you are most likely encounter are:

  • Namespace changes. E.g. Umbraco.Core has been renamed Umbraco.CMS.Core.
  • No support for older ASP.NET MVC Concepts (e.g. Ajax.BeginForm) and other legacy helpers
  • Dependency Injection is used everywhere; static helpers or manually newed up services will cause issues.

Hosting on Linux with Kestrel and Nginx

Once the database and application were migrated, I deployed the site to Ubuntu by publishing it to a folder and using SFTP to upload it to a folder on the server. Don't forget your wwwroot/media folder too.

Kestrel runs out-of-the-box with .NET 8 (it's packaged in-to the runtime), making installation a no-op and ideal for hosting a lightweight application.

Setting Up Nginx as a Reverse Proxy

Kestrel has some limitations and isn't recommended for front of house website serving. To make the website accessible via the public domain, I set up Nginx as a reverse proxy.

To install and configure Nginx as a reverse proxy for your Umbraco site, start by updating your system with

sudo apt update
sudo apt install nginx -y

Verify it’s running with sudo systemctl status nginx

Then create a new configuration file in /etc/nginx/sites-available/umbraco, define a server block that listens on port 80, and forward requests to Kestrel on http://localhost:5000.

Enable the configuration with a symbolic link to /etc/nginx/sites-enabled/, then test with sudo nginx -t and restart Nginx using sudo systemctl restart nginx.

Ensure your Kestrel application is running before restarting Nginx to avoid proxy errors. Optionally, set up HTTPS with Certbot and Let's Encrypt.

Here’s a sample Nginx configuration:

server {
    listen 80 default_server;
    server_name justaguycoding.com www.justaguycoding.com;

    location / {
        proxy_pass http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection keep-alive;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    error_page 404 /index.html;
}

NOTE: This example excludes the Lets Encrypt SSL certificate for HTTPS

Automating with Systemd

To configure Systemd to manage and auto-restart your Umbraco application, create a service file with

sudo nano /etc/systemd/system/umbraco.service

Define the service to use the Kestrel application by specifying the ExecStart directive with the path to your Umbraco DLL (e.g., /usr/bin/dotnet /var/www/publish/website.dll). Set Restart=always to ensure the service restarts on failure, and include environment variables like ASPNETCORE_URLS=http://*:5000.

Reload Systemd with

sudo systemctl daemon-reload

Then enable the service with

sudo systemctl enable umbraco.service

and finally start it with

sudo systemctl start umbraco.service

Verify it’s running with

sudo systemctl status umbraco.service

Here’s an example configuration:

[Unit]
Description=Umbraco 13
After=network.target

[Service]
User=www-data
WorkingDirectory=/var/www/publish
ExecStart=/usr/bin/dotnet /var/www/JustAGuyCodingU13.dll
Restart=always
RestartSec=5
Environment=ASPNETCORE_URLS=http://*:5000
[Install]
WantedBy=multi-user.target

Some useful commands for you:

sudo systemctl daemon-reload
sudo systemctl enable umbraco.service
sudo systemctl start umbraco.service
sudo systemctl status umbraco.service

File Permissions and Media

On Linux, file permissions are crucial. All application files were set to the www-data user for security, using:

sudo chown -R www-data:www-data /var/www/
sudo find /var/www/-type d -exec chmod 750 {} \;
sudo find /var/www/-type f -exec chmod 640 {} \;

Wrapping Up

After some trial and error, justaguycoding.com is now running smoothly on Ubuntu 22.04 LTS with Umbraco 13 and .NET 8. The website is faster, more secure, and more reliable.