On this site, you will find a step-by-step guide on deploying a Python Application using uWSGI with NGINX.
Create a Python Site with the right Python Version and ensure the App Port is correct.
For running a Python Application in production, we use The uWSGI Project, which ensures that our Application is available after a reboot.
cd /etc/uwsgi/apps-enabled/
[uwsgi] plugins = python3 master = true protocol = uwsgi socket = 127.0.0.1:8090 wsgi-file = /home/site-user/htdocs/python-project/wsgi.py # In case you're using virtualenv uncomment this: #virtualenv = /home/site-user/htdocs/python-project # Needed for OAuth/OpenID buffer-size = 8192 # Reload when consuming too much of memory reload-on-rss = 250 # Increase number of workers for heavily loaded sites workers = 4 # Enable threads for Sentry error submission enable-threads = true # Child processes do not need file descriptors close-on-exec = true # Avoid default 0000 umask umask = 0022 # Run as weblate user uid = site-user gid = site-user # Enable harakiri mode (kill requests after some time) # harakiri = 3600 # harakiri-verbose = true # Enable uWSGI stats server # stats = :1717 # stats-http = true # Do not log some errors caused by client disconnects ignore-sigpipe = true ignore-write-errors = true disable-write-exception = true
Below you see the default vhost. It’s forwarding all requests via reverse proxy to the App Port.
It’s useful for development where you use the built-in server, provided by most the Python Applications.
server { listen 80; listen [::]:80; listen 443 ssl http2; listen [::]:443 ssl http2; {{ssl_certificate_key}} {{ssl_certificate}} server_name www.domain.com; {{root}} {{nginx_access_log}} {{nginx_error_log}} if ($scheme != "https") { rewrite ^ https://$host$uri permanent; } location ~ /.well-known { auth_basic off; allow all; } {{settings}} index index.html; location /uwsgi { include uwsgi_params; uwsgi_read_timeout 3600; #uwsgi_pass unix:///run/uwsgi/app/weblate/socket; uwsgi_pass 127.0.0.1:{{app_port}}; } location / { proxy_pass http://127.0.0.1:{{app_port}}/; proxy_http_version 1.1; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_pass_request_headers on; proxy_max_temp_file_size 0; proxy_connect_timeout 900; proxy_send_timeout 900; proxy_read_timeout 900; proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; proxy_temp_file_write_size 256k; } location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|webp|zip|swf)$ { add_header Access-Control-Allow-Origin "*"; expires max; access_log on; } if (-f $request_filename) { break; } }
Replace the value of server_name with your domain.
server { listen 80; listen [::]:80; listen 443 ssl http2; listen [::]:443 ssl http2; {{ssl_certificate_key}} {{ssl_certificate}} server_name www.domain.com; {{root}} {{nginx_access_log}} {{nginx_error_log}} if ($scheme != "https") { rewrite ^ https://$host$uri permanent; } location ~ /.well-known { auth_basic off; allow all; } {{settings}} index index.html; location / { include uwsgi_params; uwsgi_read_timeout 3600; #uwsgi_pass unix:///run/uwsgi/app/weblate/socket; uwsgi_pass 127.0.0.1:{{app_port}}; } #location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|webp|zip|swf)$ { # add_header Access-Control-Allow-Origin "*"; # expires max; # access_log on; #} if (-f $request_filename) { break; } }
Restart the uwsgi service via systemctl to apply our configuration.
systemctl restart uwsgi
To check if uwsgi is listening on our requested port e.g., 8090, we use netstat:
netstat -tulpn |grep uwsgi
If everything is correct, you should see an output like this:
tcp 16 0 127.0.0.1:8090 0.0.0.0:* LISTEN 8872/uwsgi
Reboot your instance to confirm that your application is working as expected.
On this site, you will find a step-by-step guide on adding a custom Python Version to the instance.
We will add an older version Python 3.8, to our instance as an example.
The first and easiest solution for Ubuntu users would be to import the deadsnakes team Launchpad PPA.
This will always contain the latest updates for Python and all extra packages that may be required.
apt update && apt -y install software-properties-common
add-apt-repository ppa:deadsnakes/ppa -y
apt update && apt -y install python3.8
First, we need to install the required dependencies to be able to build Python 3.8 from the source.
apt update && apt -y install build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev libbz2-dev
All Python Releases can be found on the following site: https://www.python.org/downloads/
wget https://www.python.org/ftp/python/3.8.13/Python-3.8.13.tgz
tar xf Python-3.8.13.tgz
cd Python-3.8.13 ./configure --prefix=/usr --enable-optimizations
make
make altinstall
rm -rf Python-3.8.13 Python-3.8.13.tgz
apt --purge remove zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libreadline-dev libffi-dev libsqlite3-dev libbz2-dev
cp -R ~/tmp/joomla/* ~/htdocs/www.domain.com/
rm -rf ~/tmp/*
On this site, you find a guide to install Laravel on CloudPanel.
If you like the command line, you can create a Laravel Site with the following command as root user.
clpctl site:add:php --domainName=www.domain.com --phpVersion=8.2 --vhostTemplate='Laravel 10' --siteUser='john-doe' --siteUserPassword='!secretPassword!'
ssh john-doe@server-ip-address
cd htdocs && rm -rf www.domain.com
php8.2 /usr/local/bin/composer create-project --prefer-dist laravel/laravel:^10 -n www.domain.com
On this site, you find a guide to install WooCommerce on CloudPanel.
Click on + Add Site and then click on Create a WordPress Site.
On this site, you find a step-by-step guide on how to build a PHP Extension for a specific PHP Version.
apt update && apt -y install php8.1-dev
curl -O https://pecl.php.net/get/ssh2-1.3.1.tgz
tar xf ssh2-1.3.1.tgz
cd ssh2-1.3.1 phpize8.1
./configure make make install
nano /etc/php/8.1/cli/php.ini
extension=ssh2.so
nano /etc/php/8.1/fpm/php.ini
extension=ssh2.so
systemctl restart php8.1-fpm
After registering the PHP Extension, you can check if the extension is loaded for CLI and FPM correctly.
You can use grep to check if the extension is loaded:
php8.1 -m |grep 'ssh2'
If you don’t get an output, then the extension is NOT loaded.
To check if the extension is loaded for FPM, you can check the phpinfo.
Create the file t.php in the root directory.
Put the following content in the file:
<?php phpinfo();
If you don’t find information about the extension, then it’s NOT loaded.
There is currently no ionCube Loader for PHP 8.0 available.
Using ionCube encoded and secured PHP files requires a file called the ionCube Loader to be installed on the web server and made available to PHP.
The ionCube Loader extension is being shipped by default for all PHP Versions but disabled for performance reasons.
To enable ionCube Loader for a specific PHP Version, you need to enable it for CLI and FPM:
nano /etc/php/8.1/cli/php.ini nano /etc/php/8.1/fpm/php.ini
;zend_extension=ioncube_loader.so
systemctl restart php8.1-fpm
ssh john-doe@server-ip-address
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash
source ~/.bashrc
nvm install 16
nvm use 16
node -v