Ubuntu on Windows 10 for Magento Development

Find the Ubuntu App in the Windows App Store and install it.

Run the bash shell – click the app icon to run it. You will be logged in to your Ubuntu machine.

Now, you need apache, mysql, and phpmyadmin, at a bare minimum in order to start your localhost web server. You probably also want to use multiple versions of php since you will have different web sites with different production environments.

Ubuntu will give you php 7.0 by default. We will add 5.6, 7.1, and 7.2 also.

  1. Install apache 2.
    $ sudo apt-get install apache2 libapache2-mod-fcgid

    You will be prompted to type Y to complete the installation.

  2. Start the apache service.
    $ sudo service apache2 start

    if you are prompted for a password, this is your password for the windows user account you are using windows under presently. You may see an error message when you start the service that looks like the below. You can safely ignore this message.

    At this point, you should be able to find your localhost in a browser.

  3. Set up MySQL Server (or mariadb)
    $ sudo apt-get install mysql-server

    Again, you will be prompted to type Y to complete the installation

  4. Start MySQL Server
    $ sudo service mysql start

  5. Verify MySQL is running.
    $ mysql -u root -p 
     
  6. Set up PHP. We need multiple versions of PHP since we work on multiple versions of Magento: 5.6 for m1, 7.1 for 2.2, and 7.2 for 2.3. We will have 7.0 from the default Ubuntu also.
    $ sudo apt-get install php libapache2-mod-php php-xml php-gd php-mcrypt php-mysql php-intl php-curl
    Answer Y to complete the installation.
  7. Validate that php is running.
    $ a2query -m php7.0
    If it is not running, enable it:
    $ sudo a2enmod php7.0
    and restart apache:
    $ sudo service apache2 restart
    Navigate to your webroot (/var/www/html) and create an index.php file
    Type
    sudo vi index.php
    then when the editor opens, type i to begin inserting text. When you are finished typing, escape, and type wq<enter> to write and quit the editor.
    Browse to your index.php file – you should see php info in your localhost now.
  8. PhpMyAdmin
    sudo apt-get install phpmyadmin

    When the first prompt appears, press Space, Tab, and then Enter to select Apache. Select yes when asked to use dbconfig-common to set up the database. Provide your MariaDB root password Choose a password for the phpMyAdmin application itself.

    Enable the necessary PHP extensions:

    sudo phpenmod mcrypt
    sudo phpenmod mbstring

    Add this line to the bottom of /etc/apache2/apache2.conf

    Include /etc/phpmyadmin/apache.conf

    Restart Apache:

    sudo service apache2 restart
    Now you can access phpMyAdmin on the following URL: http://localhost/phpmyadmin/
    You can login using the root username and the root password you set up during the MariaDB installation.
     
  9. Alternate PHP Versions
    For the installation of PHP versions, we use the PPA maintained here. Use the below couple of commands to add the PPA to your system. You will be prompted to type Y to confirm and continue the installation.
    $ sudo apt install python-software-properties
    $ sudo add-apt-repository ppa:ondrej/php
    $ sudo add-apt-repository ppa:ondrej/apache2
    For this tutorial, we are using the PHP 5.6, PHP 7.1 and PHP 7.2 to configure with Apache web server. To use the multiple PHP versions, we will use PHP FPM and FastCGI. Let’s install the following packages on your system. You will be prompted to type Y to continue after each php install.
    $ sudo apt update
    $ sudo apt install php5.6 php5.6-fpm php5.6-xml php5.6-gd php5.6-mcrypt php5.6-intl php5.6-mysql php5.6-curl
    $ sudo apt install php7.1 php7.1-fpm php7.1-xml php7.1-gd php7.1-mcrypt php7.1-intl php7.1-mysql php7.1-curl
    $ sudo apt install php7.2 php7.2-fpm php7.2-xml php7.2-gd php7.2-mcrypt php7.2-intl php7.2-mysql php7.2-curl
    After installation, php-fpm services will not be started automatically. Use the following commands to make sure all versions of php are installed.
    $ sudo update-alternatives --config php
    and these commands to start a specific service
    $ sudo service php5.6-fpm start
    $ sudo service php7.2-fpm start
    Edit the php.ini file to enable pdo – look for the line “extension=php_pdo_mysql.dll” and remove the ; at the front of it. Do this for each version of php-fpm you installed. The files are in /etc/php/*/fpm/php.ini where * is the php version number.

    Activate fcgid
    $ sudo a2enmod actions fcgid alias proxy_fcgi
     
  10. Make a symbolic link from one of your website project files to your webroot. Your webroot is in /var/www/html in the ubuntu shell.
    $ ln -s full-path-to-web-files-on-your-pc directory-name-for-site
    I am going to add a site that needs 5.6 and one that needs 7.2
  11. Add apache config for each new vhost
    You can add a new file for each host or just add to the default 000-default.conf file. Be sure to symlink sites-available to sites-enabled. The FilesMatch directive is used to set the php version for the site.
            
    <FilesMatch>
        SetHandler "proxy:unix:/var/run/php/php5.6-fpm.sock|fcgi://localhost/"
    </FilesMatch>
        
  12. Restart Apache
  13. Edit your hosts file

Next Steps

Add SSL – https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-apache-in-ubuntu-16-04 (skip firewall step)

https://medium.com/@thomas.schmidt.0001/how-to-use-ubuntu-bash-on-windows-10-as-the-intellij-idea-terminal-334fd9a10d8c

https://getcomposer.org/download/

https:// tecadmin . net/install-redis-ubuntu/

https:// tecadmin . net/install-memcached-with-php-on-ubuntu/

comparing core_config_data

Find core_config_data differences between a production and development db.

SELECT path, value FROM (
SELECT path, value FROM your_dev_db.core_config_data
UNION ALL
SELECT path, value FROM your_prod_db.core_config_data
) tbl
GROUP BY path, value
HAVING count(*) = 1
ORDER BY path


query("select * from core_config_data where path in (
'admin/url/custom',
'admin/url/use_custom',
'carriers/ups/access_license_number',
'carriers/ups/allowed_methods',
'carriers/ups/dest_type',
'carriers/ups/dest_type',
'carriers/ups/negotiated_active',
'carriers/ups/negotiated_active',
'carriers/ups/password',
'carriers/ups/username',
'dev/css/merge_css_files',
'dev/js/merge_files',
'payment/authorizenet/cgi_url',
'payment/authorizenet/cgi_url_td',
'payment/authorizenet/login',
'payment/authorizenet/merchant_email',
'payment/authorizenet/test',
'payment/authorizenet/trans_key',
'payment/cashondelivery/active',
'payment/paypal_direct/cctypes',
'payment/paypal_direct/payment_action',
'payment/paypal_direct/sort_order',
'paypal/general/business_account',
'paypal/wpp/api_password',
'paypal/wpp/api_signature',
'paypal/wpp/api_username',
'paypal/wpp/sandbox_flag',
'shipping/origin/postcode',
'shipping/origin/region_id',
'system/currency/installed',
'web/cookie/cookie_domain',
'web/cookie/cookie_path',
'web/secure/base_js_url',
'web/secure/base_media_url',
'web/secure/base_skin_url',
'web/secure/base_url',
'web/unsecure/base_js_url',
'web/unsecure/base_media_url',
'web/unsecure/base_skin_url',
'web/unsecure/base_url')");

foreach ($result as $row) {
echo "update `core_config_data` set `value` = '" . $row['value'] . "' where `path`='" . $row['path'] . "';" . PHP_EOL;
}
?>

Bootstrap

If you are following the Front End Development theme, then you’ve got your environment set up with Node.js, Grunt, Bower, and you’ve got a Bootstrap app going.

Let’s add a bootstrap form to that index.html file and our css and javascripts.

The form is going to submit to get_primes.php and we included get_primes.js, so we need to build these files also.

Because we built with bootstrap, we have a lot of functionality built in – the css for the form is there, and jQuery is there. We really only have to design the form fields, add the javascript to handle the AJAX on submit, and build a php script to generate the repsonse.

The Prime Form in Action
The Prime Form in Action

Check out the source code: https://github.com/jnodwell/bootstraptest

Drupal on nginx

server {
    server_name example.com;
    root /var/www/drupal8; ## <-- Your only path reference.

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # Very rarely should these ever be accessed outside of your lan
    location ~* \.(txt|log)$ {
        allow 192.168.0.0/16;
        deny all;
    }

    location ~ \..*/.*\.php$ {
        return 403;
    }

    location ~ ^/sites/.*/private/ {
        return 403;
    }

    # Allow "Well-Known URIs" as per RFC 5785
    location ~* ^/.well-known/ {
        allow all;
    }

    # Block access to "hidden" files and directories whose names begin with a
    # period. This includes directories used by version control systems such
    # as Subversion or Git to store control files.
    location ~ (^|/)\. {
        return 403;
    }

    location / {
        # try_files $uri @rewrite; # For Drupal <= 6
        try_files $uri /index.php?$query_string; # For Drupal >= 7
    }

    location @rewrite {
        rewrite ^/(.*)$ /index.php?q=$1;
    }

    # Don't allow direct access to PHP files in the vendor directory.
    location ~ /vendor/.*\.php$ {
        deny all;
        return 404;
    }

    # In Drupal 8, we must also match new paths where the '.php' appears in
    # the middle, such as update.php/selection. The rule we use is strict,
    # and only allows this pattern with the update.php front controller.
    # This allows legacy path aliases in the form of
    # blog/index.php/legacy-path to continue to route to Drupal nodes. If
    # you do not have any paths like that, then you might prefer to use a
    # laxer rule, such as:
    #   location ~ \.php(/|$) {
    # The laxer rule will continue to work if Drupal uses this new URL
    # pattern with front controllers other than update.php in a future
    # release.
    location ~ '\.php$|^/update.php' {
        fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
        # Security note: If you're running a version of PHP older than the
        # latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini.
        # See http://serverfault.com/q/627903/94922 for details.
        include fastcgi_params;
        # Block httpoxy attacks. See https://httpoxy.org/.
        fastcgi_param HTTP_PROXY "";
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_intercept_errors on;
        # PHP 5 socket location.
        #fastcgi_pass unix:/var/run/php5-fpm.sock;
        # PHP 7 socket location.
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
    }

    # Fighting with Styles? This little gem is amazing.
    # location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6
    location ~ ^/sites/.*/files/styles/ { # For Drupal >= 7
        try_files $uri @rewrite;
    }

    # Handle private files through Drupal.
    location ~ ^/system/files/ { # For Drupal >= 7
        try_files $uri /index.php?$query_string;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires max;
        log_not_found off;
    }
}