Windows 10 WSL2 Ubuntu 20.04 Install Tandoor Recipes

Install TANDOOR RECIPES on Windows 10, WSL 2, Ubuntu 20.04

April 15, 2022

This procedure assumes familiarity with Windows PowerShell and Linux shell commands.

This procedure is provided as a courtesy and functioned on the author’s Windows 10 computer on April 15, 2022. Your results may be different due to variations in Windows 10 software and computer hardware.

Recommended Resources to Read First

Step 1. WSL2 and Ubuntu 20.04

1A. Verfiy WSL2 is installed using Windows Powershell as Administrator (‘PSadmin’):

wsl --status

PSadmin Desired output: PS C:\Windows\system32> wsl --status Default Distribution: Ubuntu-20.04 Default Version: 2

1B. If the output differs, follow the Ubuntu tutorial at:

    wsl --install

    # The requested operation is successful. Changes will not be effective until the system is rebooted.

1C. After reboot, go to the Microsoft App Store and download Ubuntu 20.04.4 LTS (494.5 MB download).

Microsoft Store description:

Install a complete Ubuntu terminal environment in minutes with Windows Subsystem for Linux (WSL).

1D. Control Panel – Programs and Features – Turn Windows features on or off


Virtual Machine Platform

Windows Subsystem for Linux

1E. In PC BIOS, enable virtualization. For example:

1F. After enabling virtualization in BIOS, PC will reboot.

1G. Click on Windows Start button and then start Ubuntu 20.04.4 LTS.

1H. Make sure to install Ubuntu with user ‘recipes’, or create a new user ‘recipes’ if required.


    PS C:\WINDOWS\system32> wsl -l -v
        NAME            STATE           VERSION
    * Ubuntu-20.04    Running         2

1I. From this point on, it is recommended to use the Windows Terminal Preview (‘WTP’) except when performing a Windows administrative function with PSadmin such as ‘wsl --shutdown’. See:

Windows Terminal Preview can be installed from the Microsoft Store.

1J. Verify:

WTP Desired output:

    PS C:\Users\YourUserName> wsl --status
    Default Distribution: Ubuntu-20.04
    Default Version: 2

Step 2. Enable systemd in WSL 2

2A. Please read this link:

2B. The solution is found in this link:



    cd /tmp

    wget --content-disposition \

    chmod +x /tmp/

    /tmp/ && rm /tmp/

    # exit WTP


    wsl --shutdown

2C. Start WSL2 with PSadmin:

    wsl genie -s

PSadmin expected output:

    PS C:\Windows\system32> wsl genie -s

2D. Use WTP to verify systemd with a systemctl command:

    PS C:\Users\YourUserName> wsl genie -s
    recipes@YourComputerName-wsl:~$ sudo systemctl status
    [sudo] password for recipes: xxxxxxxx
    ● - System Time Synchronized
             Loaded: loaded (/lib/systemd/system/; static; vendor preset: disabled)
             Active: active since Thu 2022-04-14 09:41:00 PDT; 4min 53s ago
                 Docs: man:systemd.special(7)

    Apr 14 09:41:00 YourComputerName-wsl systemd[1]: Reached target System Time Synchronized.

2E. WSL2 can be shutdown with PSadmin with the ‘wsl --shutdown’ command.

2F. In a new PSadmin window, the wsl ‘help’ information is available with the command ‘wsl --help’.

2G. From this point forward, Ubuntu 20.04 should operate normally as long as WSL2 is started by PSadmin with the ‘wsl genie -s’ command, followed by WTP also with the ‘wsl genie -s’ command.

Step 3. NGINX Installation

3A. The Tandoor Recipes installation steps below provide the required content for NGINX configuration. NGINX can be installed with:

    sudo apt update
    sudo apt upgrade
    sudo apt install nginx

3B. If there is another web server running on your Windows-10 computer (e.g. IIS), there may be a conflict with http port 80 (e.g. or http://localhost/). This was true for the author, so IIS was disabled as a Windows Service during Tandoor Recipes installation until the Tandoor Recipes port 8002 was functional with NGINX.

3C. Verify with, browser should display “Welcome to nginx!”.

Step 4. Install Python3.9

4A. Please see

    sudo apt update
    sudo apt install software-properties-common
    sudo apt install python3.9

4B. Verify with:

    python3.9 --version

Expected output:

    Python 3.9.X

Step 5. Clone Latest Tandoor Recipies

5A. Clone latest reposititory from GitHub:

    cd ~ 
    # should be /home/recipes
    git clone
    # on 04-15-2022 this was the 'develop' branch
    sudo mv recipes /var/www
    cd /var/www/recipes
    ls -alh # verify clone
    sudo chown -R recipes:www-data /var/www/recipes

Step 6. Set-up PIP and ENV

6A. Install pip for python3.9:

    curl -o

6B. Verify:

    python3.9 -m pip --version

Expected output:

    pip 22.0.4 from /home/recipes/.local/lib/python3.9/site-packages/pip (python 3.9)

6C. Install python3.9-venv:

    sudo apt install python3.9-venv

6D. Create virtual environment:

    python3.9 -m venv /var/www/recipes


recipes@YourComputerName:/var/www/recipes$ ls -alh

    total 2.6M
    drwxr-xr-x 1 recipes www-data 4.0K Apr 11 17:07 .
    drwxr-xr-x 1 recipes recipes  4.0K Apr 11 16:55 ..
    -rw-r--r-- 1 recipes www-data    0 Apr 11 16:55
    drwxr-xr-x 1 recipes recipes  4.0K Apr 11 17:16 bin
    -rw-r--r-- 1 recipes recipes  2.6M Apr 11 17:08
    drwxr-xr-x 1 recipes recipes  4.0K Apr 11 17:04 include
    drwxr-xr-x 1 recipes recipes  4.0K Apr 11 17:04 lib
    lrwxrwxrwx 1 recipes recipes     3 Apr 11 17:04 lib64 -> lib
    drwxr-xr-x 1 recipes www-data 4.0K Apr 11 16:55 locale
    -rw-r--r-- 1 recipes www-data 2.4K Apr 11 16:55
    -rw-r--r-- 1 recipes recipes    70 Apr 11 17:16 pyvenv.cfg
    -rw-r--r-- 1 recipes www-data  16K Apr 11 16:55
    -rw-r--r-- 1 recipes www-data 1.6K Apr 11 16:55
    -rw-r--r-- 1 recipes www-data   40 Apr 11 16:55
    -rw-r--r-- 1 recipes www-data 1016 Apr 11 16:55

note: the pyvenv.cfg file, bin folder, and lib folder, are related to the newly created virtual environment.

6E. Activate venv:

    cd /var/www
    source ./recipes/bin/activate

6F. Load env values:

    # review env prior
    export $(cat /var/www/recipes/.env |grep '^[^#]' | xargs)
    # review env after

Step 7. Install Javascript Tools (nodejs >= 12 required)

7A. Install nodejs:

    curl -fsSL | sudo -E bash -
    sudo apt install -y nodejs
    node --version
    # v16.14.2 is expected output

7B. Install npm:

    sudo npm install --global yarn
    npm --version
    #8.5.0 is expected output

Step 8. Install PostgreSQL

8A. If you already have PostgreSQL installed on your Windows 10 computer, you may need to change the Tandoor Recipes PostgreSQL port from 5432 to something else.

8B. If you already have PostgreSQL installed on your Windows 10 computer (e.g. Odoo uses PostgreSQL), it may be possible to use the already installed PostgreSQL server. This has not been verified, however.

8C. pgAdmin 4 is an excellent PostgreSQL utility that runs on Windows and Linux (

8D. Install PostgreSQL on your WSL2 Ubuntu instance:

    sudo apt install libpq-dev postgresql

8E. Verify:

    sudo systemctl status postgresql
    # look for loaded and active

Step 9. Install requirements.txt

9A. Install requirements.txt:

    cd /var/www/recipes

    sudo apt install libsasl2-dev python-dev libldap2-dev libssl-dev
    sudo apt install python3.9-dev
    sudo apt install build-essential
    /var/www/recipes/bin/pip3.9 install python-ldap
    /var/www/recipes/bin/pip3.9 install -r requirements.txt

    cd /var/www/recipes/vue

    yarn install
    yarn build

Step 10. Configure PostgreSQL

10A. Start postgresql if not running:

    sudo service postgresql status
    # if down then
    sudo service postgresql start

10B. Open psql console

note: replace ‘password’ with yoursecurepassword

    sudo -u postgres psql

    # postgres=# is expected console response

    # In the psql console:

    CREATE DATABASE djangodb;
    CREATE USER djangouser WITH PASSWORD 'password';
    GRANT ALL PRIVILEGES ON DATABASE djangodb TO djangouser;
    ALTER DATABASE djangodb OWNER TO djangouser;

    #--Maybe not necessary, but should be faster:

    ALTER ROLE djangouser SET client_encoding TO 'utf8';
    ALTER ROLE djangouser SET default_transaction_isolation TO 'read committed';
    ALTER ROLE djangouser SET timezone TO 'UTC';

    #--Grant superuser right to your new user, it will be removed later



Step 11. Download the .env configuration file and edit it accordingly

11A. Download:

    cd /var/www/recipes

    wget -O /var/www/recipes/.env

11B. Edit with nano.

note: replace ‘secretkey’ with yoursecretkey

note: TIMEZONE is from

note: replace ‘password’ with yoursecurepassword

    nano .env
    # edit





    STATIC_URL=/staticfiles/    # relative from application base path

    MEDIA_URL=/mediafiles/      # relative from application base path

11B. Load env values

    # review env prior
    export $(cat /var/www/recipes/.env |grep '^[^#]' | xargs)
    # review env after

Step 12. Continue Installation

12A. Migrate:

    cd /var/www/recipes
    bin/python3.9 migrate

12B. Revert superuser from postgres:

    sudo -u postgres psql

    #[sudo] password for recipes: xxxxxx



12C. Generate static files:

    cd /var/www/recipes

    bin/python3.9 collectstatic

    # 590 static files copied to '/var/www/recipes/staticfiles', 1656 post-processed.

    bin/python3.9 collectstatic_js_reverse

    # js-reverse file written to /var/www/recipes/cookbook/static/django_js_reverse

Step 13. Setup Web Services

13A. Create gunicorn_recipes.service:

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

    # insert

    Description=gunicorn daemon for recipes




    ExecStart=/var/www/recipes/bin/gunicorn --error-logfile /tmp/gunicorn_err.log --log-level debug --capture-output --bind unix:/var/www/recipes/recipes.sock recipes.wsgi:application


13B. Enable and Start:

    sudo systemctl enable gunicorn_recipes

    # Created symlink /etc/systemd/system/ → /etc/systemd/system/gunicorn_recipes.service.

    sudo systemctl start gunicorn_recipes

13C. Verify:

    sudo systemctl status gunicorn_recipes

    # look for 'loaded' and 'active'

Step 14. NGINX recipes.conf

14A. This differs from

    sudo nano /etc/nginx/conf.d/recipes.conf

    # insert:

    upstream recipes {
    # fail_timeout=0 means we always retry an upstream even if it failed
    # to return a good HTTP response (in case the Unicorn master nukes a
    # single worker for timing out).
            server unix:/var/www/recipes/recipes.sock fail_timeout=0;

    server {
            listen 8002;
            #access_log /var/log/nginx/access.log;
            #error_log /var/log/nginx/error.log;

            location /static {
                    #alias /var/www/recipes/staticfiles;
                    alias /var/www/recipes/static;

            location /media {
                    #alias /var/www/recipes/mediafiles;
                    alias /var/www/recipes/media;

            location / {
                    proxy_set_header Host $http_host;
                    proxy_pass http://unix:/var/www/recipes/recipes.sock;
                    proxy_set_header X-Forwarded-Proto $scheme;

14B. Check NGINX and restart:

    sudo nginx -t
    sudo systemctl reload nginx

14C. Verify at If the installation is correct, the Tandoor Recipes setup page should display (redirect to

Step 15. Debug Tools (if necessary)

15A. Useful commands:

    sudo nginx -t

    sudo systemctl reload nginx

    sudo systemctl daemon-reload

    sudo systemctl restart gunicorn_recipes.service

    sudo systemctl status gunicorn_recipes.service

    journalctl -xe

    tail -n 50 -f /tmp/gunicorn_err.log

    tail -n 50 -f /var/log/syslog

    tail -n 50 -f /var/log/nginx/error.log

    note: WPT allows multiple concurrent console windows, which is useful for tail.

15B. If NGINX is showing errors, try the simple web server on port 8000:

    cd /var/www/recipes
    ./ runserver
    # console should show all accesses and errors
    # should display Tandoor Recipes setup page

Step 17. Windows-10 Start on Boot

17A. Open Task Scheduler.

17B. Create Task:

General – Name – Tandoor Recipes WSL2 Ubuntu-20.04.4 Start on Boot

New Trigger – At startup

New Action – Program/Script – wsl, Add arguments – genie -a

Conditions – uncheck Start the task only if the computer is on AC power

Step 16. Import Recipe

16A. The import recipe function worked perfectly for:

    <End of Document>

Comments are closed.