Get Rewarded! We will reward you with up to €50 credit on your account for every tutorial that you write and we publish!

Deployment of NiceGUI application

profile picture
Author
Petr Koval Kotlov
Published
2024-04-24
Time to read
10 minutes reading time

About the author- Post-academia software developer, web enthusiast.

Introduction

NiceGUI implements a promising solution for web development in Python language. See documentaiton of NiceGUI.

NiceGUI makes use of several recent software approaches such as FastAPI, web-sockets which make its deployment different to the popular synchronous web frameworks such as Flask or Django.

I will use the domain name provided by Hetzner (reverse DNS) in order to diminish the hassle of buying a custom domain name.

This tutorial shows how to deploy a basic NiceGUI application in production on an Ubuntu server. I will use pyenv script for the installation of Python. Initially, this is more cumbersome than using apt, but it makes your installation more flexible with respect to changing Python versions.

Prerequisites

  • Basic knowledge of Linux & the terminal
  • A virtual private server (VPS) with a dedicated IPv4 address. The cheapest option will do.
  • The initial setup of Ubuntu server (version 22.04). See tutorial initial setup Ubuntu
  • Access to root user or a user with sudo permissions

Example terminology

  • Username: holu
  • Domain: example.com
  • IP address: 203.0.113.1

Step 1 - Install Python

Pyenv is an open-source software for managing the Python interpreters. See this blog post for a more detailed explanation.

Step 1.1 - Install Pyenv

  • Install the Ubuntu build tools

    sudo apt update && sudo apt install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
  • Install pyenv via

    curl https://pyenv.run | bash
  • Edit the file .profile in the home directory by appending the recommended commands.

    For example, in my case the .profile file ends with

    export PYENV_ROOT="$HOME/.pyenv"
    [[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
    eval "$(pyenv init -)"
    eval "$(pyenv virtualenv-init -)"
  • Logout and back in to apply the changes

  • Update pyenv's data with

    pyenv update

Step 1.2 - Install Python via Pyenv

  • Install Python 3.11.9 with
    pyenv install 3.11.9

To verify the installed Python interpreter:

  • Create a folder and open the new folder
    mkdir tmp && cd tmp
  • Define Python interpreter to be used within current folder
    pyenv local 3.11.9
  • Verify the version of the Python interpreter
    python --version
  • Now that you know that everything works, you can use rm -r tmp to delete the directory.

Step 2 - Create the application

We will create a simple application with NiceGUI and see how it runs in development.

Step 2.1 - Create the main file

  • Create a root directory for the application and open the nicegui-test directory

    mkdir nicegui-test && cd nicegui-test
  • Create a file nicegui-test/main.py with the following content

    If you want to use a different port, replace 5000 with a port of your choice.

    """."""
    from nicegui import ui
    import numpy as np
    from matplotlib import pyplot as plt
    
    
    def main() -> None:
        """."""
    
        # Add a "settings" icon
        ui.icon('settings')
    
        # Add a matplotlib figure
        with ui.pyplot(figsize=(3, 2)):
            x = np.linspace(0.0, 5.0)
            y = np.cos(2 * np.pi * x) * np.exp(-x)
            plt.plot(x, y, '-')
    
        ui.notify('my notification')
    
        # Add an interactive 3D scene with two spheres
        with ui.scene(width=320, height=240) as scene:
            scene.spot_light(distance=100, intensity=0.6).move(-10, 0, 10)
            with scene.group() as group:
                scene.sphere().move(-1.0, 0.0, 0.0).draggable()
                scene.sphere().move(+2.0, 0.0, 0.0)
                group.rotate(30.0, 0.0, 0.0)
    
    # Set the port to 5000
    if __name__ in ('__main__', '__mp_main__'):
        main()
        ui.run(port=5000)

Step 2.2 - Run the application in development mode

Let's run main.py in the development mode to see what it does.

  • Step into the nicegui-test directory from the previous step.
  • Define the Python interpreter to be used with
    pyenv local 3.11.9
  • Create a local Python environment
    python -m venv env
  • Activate the local Python environment
    source env/bin/activate
  • Install the NiceGUI and matplotlib
    pip install nicegui matplotlib
  • Run the app
    python main.py

The web app should be served from your VPS. The <address>:<port> combination is shown in terminal. The example above used port 5000, so it would be something like 203.0.113.1:5000. You might need to add an inbound rule to your firewall allowing TCP traffic on port 5000. If this is done or there is no firewall activated in your VPS, then please direct to the browser to see the screen.

Development deployment in browser

Note the settings icon, the matplotlib figure, and the interactive 3D scene with two unadorned spheres. One of the spheres (left) could be dragged with the mouse. Moreover, you could interact with the whole scene (rotate, zoom, pan) with your mouse.

Step 3 - Create the system service

After playing with the development deployment, we will want to deploy the app in production. The good news is that NiceGUI is using the production-grade web server uvicorn under the hood. Our part of the work is to configure the systemd service nicegui-test. The service nicegui-test will automatically run after restarts.

Moreover, we will split the application and its deployment by using a little script asgi.py. The script defines the port and splits the incoming requests (from different browsers or tabs) serving separate responses.

  • Create the file nicegui-test/asgi.py (next to main.py). The file asgi.py should contain

    from main import main
    from nicegui import ui
    
    @ui.page('/')
    def main_page() -> None:
        main()
    
    ui.run(port=5129)
  • Create a system service file

    sudo nano /etc/systemd/system/nicegui-test.service

    Add the following content

    Replace holu with your own username and /home/holu/nicegui-test with the actual path to your nicegui-test directory.

    [Unit]
    Description = Running a test of NiceGUI.
    After = network.target
    
    [Service]
    User = holu
    Group = www-data
    WorkingDirectory = /home/holu/nicegui-test
    Environment="PATH=/home/holu/nicegui-test/env/bin"
    ExecStart=/home/holu/nicegui-test/env/bin/python asgi.py
    
    [Install]
    WantedBy=multi-user.target
  • Start the newly created service

    sudo systemctl start nicegui-test
  • Verify the service is running

    sudo systemctl status nicegui-test
    • The <address>:<port> combination will be shown in the output.
    • You might need to add an inbound rule to your firewall allowing TCP traffic on port 5129.
    • Direct to address:5129 in your browser and see the application screen as in case of development deployment.
  • Enable the automatic start of the service

    sudo systemctl enable nicegui-test

Step 4 - Configuration of nginx

Next challenge is to configure the domain name. We will use nginx software. After this step, the application will be served via the standard HTTP port 80.

  • Install nginx with

    sudo apt install nginx
  • Verify that nginx is functional: Direct to the (IP) address in the browser and see the default page

    Default nginx page

  • Create a new configuration file

    sudo nano /etc/nginx/sites-available/nicegui-test.conf

    Add the following content:

    Replace example.com with your domain or IP address. If you add an IP address, traffic will be served unencrypted (only HTTP; HTTPS not possible).

    If you have a Hetzner server, you could use the automatic reverse DNS name as domain.

    Click here to see how to find the reverse DNS in Hetzner Cloud Console.

    Networking tab at Hetzner

    server {
        listen 80;
        server_name example.com;
    
        location / {
              include proxy_params;
                    proxy_pass http://localhost:5129;
                    proxy_http_version 1.1;
                    proxy_set_header Upgrade $http_upgrade;
                    proxy_set_header Connection "Upgrade";
        }
    }
  • Remove all files from the sites-enabled folder

    sudo rm /etc/nginx/sites-enabled/*
  • Create symbolic link in sites-enabled folder

    sudo ln -s /etc/nginx/sites-available/nicegui-test.conf /etc/nginx/sites-enabled
  • Verify the nginx configuration

    sudo nginx -t
  • Restart the nginx service via

    sudo systemctl restart nginx
  • Verify the NiceGUI application is served at the (IP) address at standard port 80

    • Direct to the IP address of the server without specifying any port number.
    • Note that you might need to hard-reload the page with Ctrl+F5 key combination.

Step 5 - Obtaining SSL certificate (HTTPS)

Finally, lets set up an SSL certificate for our experimental web page. This is possible to do via the "Let's Encrypt" project by Linux foundation.

A good video tutorial on the topic is produced at Tony Teaches Tech.

Below you will find the instructions from this tutorial with some extra explanations applicable to this production deployment.

In order to serve via HTTPS, we use certbot.

  • Install snap package manager
    sudo apt update && sudo apt install snap snapd
  • Set up the snap registry via
    sudo snap install core; sudo snap refresh
  • Install certbot via
    sudo snap install --classic certbot
  • Use certbot for ordering and setting up the SSL certificate. Start an interactive session with
    sudo certbot --nginx

The certbot will ask for an e-mail address and the domain name for which the certificate will be issued. The certbot will ensure the ownership of the domain name and generate the certificate. As a result of a successful certbot run, the following configurations will be done:

  • The nginx configuration at /etc/nginx/sites-available/nicegui-test.conf.

If the configuration was simple as in the section above, then it will be extended with redirection instructions.

Click here to view an example nicegui-test.conf file.
server {
        server_name example.com;

        location / {
                include proxy_params;
                proxy_pass http://localhost:5129;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "Upgrade";
        }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

server {
    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


        listen 80;
        server_name example.com;
    return 404; # managed by Certbot


}

  • A periodic service for the automatic certificate renewal will be added. You can verify this configuration with

    sudo systemctl list-timers

You can view the configuration of the timer and service in these files:

  • /etc/systemd/system/snap.certbot.renew.timer
  • /etc/systemd/system/snap.certbot.renew.service

Conclusion

Great, you did it! This was a basic introduction to deploying a test NiceGUI application on Ubuntu 22.04 by using pyenv, systemd, nginx, and certbot.

License: MIT
Want to contribute?

Get Rewarded: Get up to €50 in credit! Be a part of the community and contribute. Do it for the money. Do it for the bragging rights. And do it to teach others!

Report Issue
Try Hetzner Cloud

Get 20€ free credit!

Valid until: 31 December 2024 Valid for: 3 months and only for new customers
Get started
Want to contribute?

Get Rewarded: Get up to €50 credit on your account for every tutorial you write and we publish!

Find out more