added up to 2019 posts

This commit is contained in:
Matthew Tran 2023-07-09 23:59:28 -07:00
parent f74311598b
commit 5bf4b7c49f
33 changed files with 737 additions and 0 deletions

View File

@ -0,0 +1,601 @@
---
title: Setting Up A WordPress Server
date: 2019-08-18
categories: how-to projects
excerpt: Just about everything you need to know about setting up a WordPress server yourself.
header:
teaser: /assets/img/2019/wp_test.jpg
---
Getting started with hosting your own website has really never been easier. However, while getting started is just a few commands away, getting something like WordPress up and running at full functionality can seem like a daunting task. When I set up my web server, I came across so many little hiccups and it felt like there was always something else to consider. Security was my main concern, but so was speed and SEO optimization. After all that I could finally focus on making content. This post will be my attempt at a comprehensive how-to combining all the things Ive learned along the way on setting up my very own WordPress site from scratch.
## Getting Your Own Domain
Theres really no shortage of different domain registrars out there to buy a domain from, but in the end I decided to use [Google Domains](https://domains.google) because it has the cleanest user experience, very competitive pricing, and doesnt try to sell you anything more than just a domain. For someone who is just starting out making a website and doesnt need any extra functionality, its an excellent choice. As of the time of writing, I own both [matthewlamtran.com](https://matthewlamtran.com) and [matthewtran.dev](https://matthewtran.dev) and it only costs $12 a year for each domain. Im sure there are better choices out there, but this is the one Im sticking with. Also, make sure you turn on auto-pay or remember to pay the annual fee because your domain can go up for sale again, where it will likely get picked up by someone else.
If you dont want to buy a domain yet, there are free DNS services out there, like [dynu.com](https://www.dynu.com), where you can get a free domain that looks something like `<your name>.<free dns provider>.com`. I dont use it anymore, but to each their own.
## Self-Hosting vs. Using a Hosting Service
When I first bought [matthewlamtran.com](https://matthewlamtran.com) over a year ago, I had to choose between hosting a website myself or using one of a seemingly limitless number of hosting services. Since I was just getting started with making my own website and didnt expect very much traffic, if any at all, I decided to host my website on a Raspberry Pi at home. Some of the benefits of hosting at home are total control over your own server, lower costs, and a greater understanding of the internal workings of a web server. However, it also makes you responsible for the security and maintenance and theres no customer support to call if something goes wrong.
However, as my website grows, I will likely switch over to a hosting service because I will become limited by the internet speeds available at my home (Im looking at you Charter Spectrum with those low upload speeds) and also by the scalability of my server. Electricity costs also become a concern as server load increases. For now and for the foreseeable future though, Im sticking to running my own server. If you want to use a hosting service, you should still continue reading because you can still learn a thing or two from my experience.
## Redirecting a Domain Name to Your Own IP Address
Underneath the pretty website names you type into your browser is the Domain Name Service (DNS). It matches every domain name to an IP address, which in turn locates the web server in cyberspace. Theres also two different address types: IPv4 and IPv6. IPv6 is needed because, in our growing digital age, we will eventually run out of IPv4 addresses. For now, Ill just cover IPv4, but the instructions should be applicable to IPv6 if necessary.
First, go to a website like [whatismyip.com](https://www.whatismyip.com) while on a device using the same internet that your server will be on. Record the IP address.
Now login to the domain registrar where you bought your domain, or the free DNS service if youre using that. Im using Google Domains, but these instructions should be applicable to other registrars.
{% include figure image_path="/assets/img/2019/googledomains_1.jpg" %}
Click on “Manage”.
{% include figure image_path="/assets/img/2019/googledomains_2.jpg" %}
Click on “DNS”.
{% include figure image_path="/assets/img/2019/googledomains_3.jpg" %}
Finally scroll all the way down and add two entries to “Custom resource records.” Replace the IP address with your own recorded IP address.
DNS records take some time to update, around 20 minutes for Google Domains. To check if the DNS is updated, try the following command in your terminal (“-n” instead of “-c” for Windows):
{% highlight bash %}
ping -c 5 <domain name>
{% endhighlight %}
If it all works out, you should see your IP address from earlier!
If your Internet Service Provider (ISP) doesnt have a static IP option, which is pretty much most residential internet plans, then this IP address will change every once in a while, in which case youll need to repeat the redirect process again. Pretty much the only ISP available in my area is Charter Spectrum, whose business and static IP options are unreasonably expensive for now, so Im sticking to manually updating the DNS records for now. Luckily, my IP address pretty much only changes once a year, so Im good. If you want to look into it, theres dynamic DNS services out there that will do the updates and stuff for you. Now onto the actual web server setup part!
## What Youll Need
- computer that you can leave on 24/7 (I recommend a Raspberry Pi if youre just starting out)
- microSD card or USB flash drive for installing the OS
- an ethernet cable (I dont recommend using WiFi because of reliability and speed)
## Installing the OS
Linux powers a surprisingly large part of the internet. Generally speaking, its faster, more secure, and ultimately easier to use. Even more, most distros are completely free and open-source. It was a pretty easy choice going with Linux, but since I am admittedly still pretty new to the world of Linux distros, I picked the most familiar distro, Ubuntu Server. They also have a version for the Raspberry Pi, so if you ever want to upgrade your server to a full size PC or something, it should be a relatively simple transition.
The process of installing an OS on the Raspberry Pi has been done to death, but it basically involves downloading the OS from the website, flashing it to a microSD card using something like [Etcher](https://www.balena.io/etcher/), and then finally plugging it into the Pi.
Installing Ubuntu Server onto a normal PC is pretty similar, but instead flashing to a flash drive, plugging into the computer, and going through the setup process.
## Initial Setup
Now plug in your server and connect the ethernet cable from your server to your router. Its possible to then figure out the IP using nmap (`sudo nmap -sP 192.168.0.1/24` on MacOS) to SSH into it, but out of convenience I just hooked up a monitor and keyboard to my server and logged in with the default username and password (both “ubuntu”).
I cannot stress enough the importance of having a strong password for everything, especially when setting up a web server. To change your password, run the following:
{% highlight bash %}
passwd
{% endhighlight %}
Now we need to update everything so run:
{% highlight bash %}
sudo apt update && sudo apt upgrade
{% endhighlight %}
`update` updates the list of packages and their versions while `upgrade` does the actual upgrading of the packages to their latest versions. Ubuntu Server does this update process automatically, but it doesnt hurt to check every once in awhile.
SSH should be enabled by default, but just in case, run:
{% highlight bash %}
sudo apt install openssh-server
{% endhighlight %}
I usually install a text editor at this point, which in my case is vim. You can use nano, but I think its worth it to learn vim.
{% highlight bash %}
sudo apt install vim
{% endhighlight %}
For future reference, I tend to run a lot of commands from the home directory. I will assume you have basic knowledge of vim. All you really need to know is press esc then type `wq` to save and quit and also press i to enter typing mode. Ill also assume you know how to use `cd` to change directories and all that. The basics of getting around a terminal really.
### Setting Up a Static IP
Just like how your external IP address changes, every device on your local networks internal IP address can change too. First, well setup a static IP on your server. Run the following:
{% highlight bash %}
cd /etc/netplan
ls
{% endhighlight %}
There should be a .yaml file in the directory. Were going to edit it.
{% highlight bash %}
vim <file name>.yaml
{% endhighlight %}
Change it from something that looks like this:
{% highlight yaml %}
network:
version: 2
ethernets:
eth0:
dhcp4: false
{% endhighlight %}
To something like this:
{% highlight yaml %}
network:
version: 2
ethernets:
eth0:
dhcp4: false
addresses: [192.168.0.***/24]
gateway4: 192.168.0.1
nameservers:
addresses: [8.8.8.8,8.8.4.4]
{% endhighlight %}
Keep in mind that what you put under “addresses” and “gateway4” can change slightly depending on your network, but running “ifconfig” can help you figure out what the right values are. The last 3 digits of the address in “addresses” (the \*\*\*), can be pretty much whatever you want up to 255. For more details check [here](https://linuxconfig.org/how-to-configure-static-ip-address-on-ubuntu-18-04-bionic-beaver-linux). Now run:
{% highlight bash %}
sudo netplan apply
{% endhighlight %}
Now we need to head over to your routers admin page, usually located at something like 192.168.0.1. Every router is a little different but the gist is that were going to assign the MAC address of our servers ethernet to the specific IP address we listed under “addresses,” without the /24.
At this point I like to run a good old `sudo reboot`, disconnect the monitor and keyboard, and head over to my laptop to complete the rest of the setup process. Congrats, your server is headless! To login to your server you can SSH into it (you might need to install a SSH client like Putty if youre on Windows).
{% highlight bash %}
ssh ubuntu@<ip address>
{% endhighlight %}
## Installing the LEMP Stack
The LEMP stack consists of Linux, Nginx, MySQL, and PHP. Its the backbone of pretty much any web server. Youll hear a lot about LAMP, which is similar, but uses Apache instead of Nginx. For its speed and recency, Ive found Nginx to be a better choice for my use case and this tutorial will reflect that. One thing to keep in mind about Nginx is that most tutorials out there assume you use Apache, so just add Nginx to your search query and youll be good.
### Installing Nginx
{% highlight bash %}
sudo apt install nginx
{% endhighlight %}
Now we need to allow Nginx through the firewall.
{% highlight bash %}
sudo ufw allow 'Nginx Full'
sudo ufw enable #this might warn about disrupting ssh, but it's fine
sudo ufw status
{% endhighlight %}
Youll probably want Nginx to start up whenever your server restarts.
{% highlight bash %}
sudo systemctl enable nginx
{% endhighlight %}
{% include figure image_path="/assets/img/2019/nginx_default.jpg" %}
Nows a good time to test your Nginx installation. Head over to a web browser and type in your servers IP address (the one you use for SSH). If you see something like the right image, youre good!
Nows also a good time to port forward web requests from the outside world to your server. If youve ever setup a Minecraft server, then this should be easy. If not, Googling your routers model plus “port forward” should lead you in the right direction. Youll want to forward requests from port 80 (HTTP) and port 443 (HTTPS) to your servers internal IP address. When thats done try typing in your domain name to your browser and you should see the same page as before!
#### Setting Up Server Blocks
Currently Nginx is routing every request to the default server block, whose files are stored in `/var/www/html`. However its good practice to setup a server block for each website youre hosting (even if its only one). For example, the files for my server are stored in `/var/www/matthewtran.dev/html`. Whats super cool is that this allows you to host multiple websites on the same server (although you might not want to for security reasons, but it depends). To make things easier to read Im going to use **matthewtran.dev** as the domain for my examples, but be sure to change **matthewtran.dev** to whatever your domain is when you do this.
First, Nginx uses the user “www-data” when interacting with the files on your website. In order to avoid file permission errors later with WordPress, well add “ubuntu” to the same user group as “www-data”.
{% highlight bash %}
sudo usermod -a -G www-data ubuntu
{% endhighlight %}
Now lets make the appropriate directories and assign proper permissions.
{% highlight bash %}
sudo mkdir -p /var/www/matthewtran.dev/html
sudo chown -R $USER:www-data /var/www/matthewtran.dev/html
{% endhighlight %}
I generally like to remove the default html folder at this point.
{% highlight bash %}
sudo rm -r /var/www/html
{% endhighlight %}
For testing lets create a file named index.html inside this new html folder. You can pretty much put any old html code. Heres literally what I put:
{% highlight bash %}
Welcome to matthewtran.dev!
{% endhighlight %}
Now we need to tell Nginx about this new server block we made.
{% highlight bash %}
cd /etc/nginx/sites-available
{% endhighlight %}
Add the following to a new file named “matthewtran.dev”
{% highlight bash %}
server {
listen 80;
listen [::]:80;
root /var/www/matthewtran.dev/html;
index index.php index.html index.htm;
server_name matthewtran.dev www.matthewtran.dev;
location / {
try_files $uri $uri/ /index.php?q=$uri&$args;
}
}
{% endhighlight %}
Now we link this new config file to the sites-enabled folder.
{% highlight bash %}
sudo ln -s /etc/nginx/sites-available/matthewtran.dev /etc/nginx/sites-enabled/
{% endhighlight %}
I also like to unlink the default enabled site at this point.
{% highlight bash %}
sudo rm /etc/nginx/sites-enabled/default
{% endhighlight %}
If youre going to add more sites, its also a good idea to uncomment this line in /etc/nginx/nginx.conf.
{% highlight bash %}
server_names_hash_bucket_size 64; #uncomment this one
{% endhighlight %}
Finally, we need to check our config files and restart (reload works too) Nginx to apply these updates.
{% highlight bash %}
sudo nginx -t
sudo systemctl restart nginx
{% endhighlight %}
#### Enabling HTTPS!
Enabling HTTPS on your website is an incredibly important step. Luckily, its pretty easy to do (and free).
{% highlight bash %}
sudo apt install python-certbot-nginx
sudo certbot --nginx -d matthewtran.dev -d www.matthewtran.dev
{% endhighlight %}
Again, make sure to change **matthewtran.dev** to your domain name. Youll need to enter your email, which Lets Encrypt uses to tell you if your certificates are about to expire, in which case youll need to use a good old `sudo certbot renew`. We can also make that happen automatically.
{% highlight bash %}
sudo crontab -e
{% endhighlight %}
Add this line to the bottom.
{% highlight bash %}
0 12 * * * /usr/bin/certbot renew --quiet
{% endhighlight %}
Now head over to your web browser and head to your domain. You should see that its now secured using HTTPS!
### Installing MySQL
{% highlight bash %}
sudo apt install mysql-server
sudo mysql_secure_installation
{% endhighlight %}
Youll be asked to set a new set a password for a root user. Theres a bunch of questions after that I just said yes to because itll increase security. Now we need to allow logging in to the root user using a password.
{% highlight bash %}
sudo mysql
{% endhighlight %}
{% highlight sql %}
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '<your password>';
mysql> FLUSH PRIVILEGES;
mysql> exit
{% endhighlight %}
Now if you try `sudo mysql`, it should deny you, but try `mysql -u root -p` and you should be able to login.
Aside: After all this setup, Ive realized that I didnt actually need to enable logging into root and disabling logging into root from phpMyAdmin later. Using SQL commands, I can grant the appropriate permissions for the user that has access to my WordPress database as well as not giving all the permissions to the phpMyAdmin user. This way, even if someone hacks into my phpMyAdmin, they cant login into any account that has a dangerous level of permissions. You know, Ill go do that right now.
### Installing PHP
{% highlight bash %}
sudo apt install php-fpm php-mysql
{% endhighlight %}
Now we need to tell Nginx to use PHP, so head over to your website config file in `/etc/nginx/sites-available`. Update it to look something like this (youll notice a bunch of extra lines that relate to HTTPS but dont worry about those):
{% highlight bash %}
server {
listen 80;
listen [::]:80;
root /var/www/matthewtran.dev/html;
index index.php index.html index.htm;
server_name matthewtran.dev www.matthewtran.dev;
location / {
try_files $uri $uri/ /index.php?q=$uri&$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
{% endhighlight %}
Like before, restart nginx using `sudo nginx -t` and `sudo systemctl restart nginx`.
Now head over to your websites html folder (the one with index.html in it) and make a new file called info.php and write this in it:
{% highlight php %}
<?php
phpinfo();
{% endhighlight %}
Now if you go to `<your domain name>/info.php`, you should see a page that looks like this:
{% include figure image_path="/assets/img/2019/phpinfo.jpg" %}
If everythings working, its a good idea to remove info.php because it tells a would be hacker a lot about your website, which could be used to exploit security vulnerabilities.
Congrats! Youve installed a full LEMP stack!
## Installing phpMyAdmin
{% highlight bash %}
sudo apt install phpmyadmin
{% endhighlight %}
The installation will tell you to choose between Apache and something else, but just press tab then enter to skip that. You also need to make a password for an account with username “phpmyadmin”. Use default settings for any other questions.
{% highlight bash %}
sudo ln -s /usr/share/phpmyadmin /var/www/matthewtran.dev/html/<str>
{% endhighlight %}
A lot of bots and hackers like to scan websites to see if phpMyAdmin is installed, after which they may perform a brute force attack on the login. Lets make it harder for them by putting something random in place of `<str>`. Some people (i.e. younger me) tend to just put “phpMyAdmin”. Dont do that.
Now head over to `matthewtran.dev/<str>`, again replacing **matthewtran.dev** with your domain name, and you should see the phpMyAdmin login page like below:
{% include figure image_path="/assets/img/2019/phpmyadmin.jpg" %}
Try logging into the users root or phpmyadmin with the passwords you set to see if everythings working.
Now log into the root account (or the phpmyadmin account if you grant proper permissions to it through MySQL or the root account in phpMyAdmin) because we need to create a database for WordPress.
{% include figure image_path="/assets/img/2019/phpmyadmin_1.jpg" %}
Click on “New”.
{% include figure image_path="/assets/img/2019/phpmyadmin_2.jpg" %}
Enter a name for your WordPress database, like “wpdata”, and press “Create”.
{% include figure image_path="/assets/img/2019/phpmyadmin_3.jpg" %}
Click on “Privileges”.
{% include figure image_path="/assets/img/2019/phpmyadmin_4.jpg" %}
Click on “Add user account”.
{% include figure image_path="/assets/img/2019/phpmyadmin_5.jpg" %}
Finally, enter a username for your WordPress database user account, pick localhost under “Host name:” and enter a strong password. You will provide these account details to your WordPress installation later.
### Disabling Root Login
Lets secure phpMyAdmin further by disabling the root login.
{% highlight bash %}
sudo vim /etc/phpmyadmin/conf.d/pma_secure.php
{% endhighlight %}
Add this to it, taking care to make any random 32 character string in place of `<random string>`.
{% highlight php %}
<?php
$cfg['blowfish_secret'] = '<random string>';
$i=0;
$i++;
$cfg['Servers'][$i]['auth_type'] = 'cookie';
$cfg['Servers'][$i]['AllowNoPassword'] = false;
$cfg['Servers'][$i]['AllowRoot'] = false;
?>
{% endhighlight %}
### HTTP Basic Authentication
To prevent brute force attacks in the case of someone finding your phpMyAdmin login page, lets add another layer of authentication before anyone even gets to that page. First you need to come up with another secure password, different from all the other ones youve used of course, and run it through the following when it asks:
{% highlight bash %}
openssl passwd -apr1 > pma_passwd
{% endhighlight %}
The OpenSSL utility outputs a really long hash of your password, which well send to the file pma\_passwd for ease of use. Now edit that file and make it look something like this:
{% highlight bash %}
<username>:<hash>
{% endhighlight %}
Replace `<username>`; with one of your choosing. `<hash>` is the hash that was already there when you opened the file. Now lets move this to the nginx folder.
{% highlight bash %}
sudo mv pma_passwd /etc/nginx
{% endhighlight %}
Remember that config file from earlier in `/etc/nginx/sites-available`? Lets edit it and add a couple lines so it looks like this:
{% highlight bash %}
server {
# other code
# replace <str> with your <str> from earlier
location /<str> {
auth_basic "phpMyAdmin Login";
auth_basic_user_file /etc/nginx/pma_passwd;
}
# other code
}
{% endhighlight %}
Now restart Nginx again (`sudo nginx -t` and `sudo systemctl restart nginx`) and try to access your phpMyAdmin screen again and youll see something like this:
{% include figure image_path="/assets/img/2019/auth_basic.jpg" %}
Enter the username and password you used and you should be in. Congrats, your phpMyAdmin is now pretty secure!
This should deter bots since, as far as my logs from my WordPress login page show, they tend to get the 401 error and then leave. And yes, we will be securing the WordPress login page later too.
## Installing WordPress
With everything in place, we finally get to the setup of WordPress itself. We start by downloading and unzipping the source files for WordPress.
{% highlight bash %}
wget -O latest.zip https://wordpress.org/latest.zip
unzip latest.zip
{% endhighlight %}
The resulting wordpress folder contains all the WordPress files which we will now move into the html folder of your website. Delete everything in that folder and then move the WordPress files over.
{% highlight bash %}
sudo rm -r /var/www/matthewtran.dev/html
sudo mv wordpress/* /var/www/matthewtran.dev/html
{% endhighlight %}
Now head over to your website and you should see the WordPress installation screen. Its a pretty straightforward process. Just follow through all the instructions, taking care to give it the username and password for the account for the WordPress database from earlier. Also youre going to create an administrator account for your website so make sure to pick a username that isnt “admin” and a very strong password as always.
Congratulations! Youve done the basic setup of your WordPress server. Now onto fixing some of the little issues that might pop up and some recommendations.
### Fixing File Permissions
First, lets change the group of every file to www-data.
{% highlight bash %}
sudo chown -R $USER:www-data /var/www/matthewtran.dev/html
{% endhighlight %}
To prevent an error about asking for FTP credentials, we need to modify `wp-config.php`. Go ahead and open it in Vim and at the very bottom of the file add the following.
{% highlight php %}
define('FS_METHOD','direct');
{% endhighlight %}
Chances are you wont be able post or change your themes or anything because of permission errors. Lets fix those.
{% highlight bash %}
cd /var/www/matthewtran.dev/html
sudo find ./ -type f -exec chmod 664 {} +
sudo find ./ -type d -exec chmod 775 {} +
sudo chmod 660 wp-config.php
{% endhighlight %}
This sets the proper permissions so WordPress is able to modify everything and update itself. Notice that we did `chmod 660` on wp-config.php. That file actually stores the credentials for your WordPress database in plaintext, so its imperative that no one except WordPress can access it. Well be adding a bit more security to it soon.
### Securing Important Files
You may have noticed that anyone can get into your login page simply by typing `<domain>/wp-login.php` or `<domain>/wp-admin` (`wp-admin` actually redirects to `wp-login.php`). There are plugins like Jetpack and WordFence (which I highly recommend installing) that help secure your site against brute force attacks but lets add another layer of security. The instructions for this are pretty much the same as when we secured phpMyAdmin.
{% highlight bash %}
openssl passwd -apr1 > wp_passwd
{% endhighlight %}
Like before, edit `wp_passwd` with a username.
{% highlight bash %}
sudo mv wp_passwd /etc/nginx
{% endhighlight %}
Now lets enable authentication in the config file in /etc/nginx/sites-available. Well also deny access to wp-config.php outright so no one can access it.
{% highlight bash %}
server {
# other code
location /wp-config.php {
deny all;
}
location /wp-login.php {
auth_basic "WordPress Login";
auth_basic_user_file /etc/nginx/wp_passwd;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
# other code
}
{% endhighlight %}
Now lets restart Nginx and test it out. If you try `<domain>/wp-config.php` you should get a 403 error. If you try `<domain>/wp-login.php` you should see a place to enter a username and password just like with phpMyAdmin. Perfect!
### Check Site Health
Now login into your WordPress installation and go to the Site Health page under Tools. There you can see if theres anything else that might be wrong. This tutorial pretty much covers all the problems Ive seen while doing this whole setup on Ubuntu Server, so you should be fine. You might be missing some PHP packages like Imagick, which you should be able to install with a simple `sudo apt install php-<pkg name>`. Google is your friend here. Sometimes a good `sudo reboot` is necessary to fix any latent problems.
### Recommended Plugins
One thing to keep in mind with plugins is that you should make sure theyre always updated because of potential security vulnerabilities. Just like how you wouldnt install a shady or very outdated app on your computer, you shouldnt install one on WordPress. Even themes can have vulnerabilities. That being said, heres some plugins I recommend:
- Jetpack
- Wordfence
- Akismet Anti-Spam
- MonsterInsights
- WP Super Cache
- Yoast SEO
### SEO Optimization and Analytics
Something you might hear about a lot online is SEO optimization. This is so that search engines like Google will rank your website higher, making it more likely for people to find, and ultimately giving your website more reach. There are many things to consider, but I think the Yoast SEO plugin is a pretty good starting point for learning about the various aspects of optimizing your website.
You might also want to keep track of how your website is doing in terms of visitors. The Jetpack plugin, which also provides a level of security, has some basic analytics of your website. I used Google Analytics before on my other website and was delighted to find out about the MonsterInsights plugin which links to your Google Analytics account and gives pretty good information about your website.
I also use the Google Search Console to also keep track of how my websites are showing up in searches (current count: 0).
### Speed Optimization
Now you may realize that when opening your website that its quite slow. The reason for this is that WordPress regenerates your website for every visitor. The plugin WP Super Cache fixes this problem by generating your website and storing it in a cache which then gets served to visitors. This vastly sped up my website, but I do have to press “Delete Cache” every once in awhile when my website isnt updating properly. One big thing to keep in mind is that images are huge, so make sure to shrink them down and compress them (like by converting to JPEG). I like to keep all my pictures under 50kB if I can. For privacy reasons, make sure you remove all the meta data from pictures before uploading. I use ImageOptim when Im using my MacBook, but Im pretty sure a Windows equivalent exists.
Sometimes the bottleneck for speed on your website comes from the server itself. You can use tools like `htop` and `iotop` to analyze your system under load and see where the slowdowns are. Currently, my storage system is the slowest part, which is to be expected. Im going to definitely upgrade my server during the next big sale.
### Security
There are so many more ways to improve the security of your website, not all of which Ive even implemented. What Ive provided so far is a pretty good start at a secure site. Theres more to do but after this point its more of the little things, dealing with more permissions and what not. If you want to learn even more about securing your site, Id recommend checking out some of the links below.
- <https://www.wpbeginner.com/wordpress-security/>
- <https://bjornjohansen.no/block-access-to-php-files-with-nginx>
- <https://lamosty.com/2015/04/14/securing-your-wordpress-site-running-on-nginx/>
One thing to keep in mind is that if youre using Jetpack or the WordPress app, you need to allow access to xmlrpc.php. Its technically a vulnerability, but Jetpack and Wordfence protect you from it.
### Backing Up Your Server
Theres many backup plugins out there, but its good to know how to backup your WordPress installation manually just in case. Basically just copy your entire html file to a safe place. Then login to phpMyAdmin using the account you made for WordPress, click on the database, then export and download the .sql file. Dont worry about all the errors that show up, just click ignore all.
Restoring is also relatively simple, just copy over the html folder and then head to phpMyAdmin, login, make a new database, and import the .sql file.
## Conclusion
Congratulations! Youve just set up your very own WordPress server from scratch. Its quite the journey but its rewarding in the end. Now go off and install themes, make posts, or really anything. WordPress is quite an impressive platform and you can do so much on it. Good luck!
#### Sources (Check these out for more details!)
- <https://linuxconfig.org/how-to-configure-static-ip-address-on-ubuntu-18-04-bionic-beaver-linux>
- <https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-php-lemp-stack-ubuntu-18-04>
- <https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-18-04>
- <https://www.digitalocean.com/community/questions/wordpress-and-nginx-404-errors-all-but-home-page>
- <https://www.nginx.com/blog/using-free-ssltls-certificates-from-lets-encrypt-with-nginx/>
- <https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-phpmyadmin-with-nginx-on-an-ubuntu-18-04-server>
- <https://www.freshwpthemes.com/tutorial/how-to-create-a-database-for-wordpress/>
- <https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/>

View File

@ -0,0 +1,48 @@
---
title: CS61C - Computer Architecture
date: 2019-12-11
categories: school
excerpt: A course with a bit of an information overload about the big ideas of computer architecture that ended up being one of my favorite courses.
header:
teaser: /assets/img/2019/61c_mbothighres.jpg
gallery:
- image_path: /assets/img/2019/61c_mbot0.jpg
- image_path: /assets/img/2019/61c_mbot1.jpg
- image_path: /assets/img/2019/61c_mbot2.jpg
gallery2:
- image_path: /assets/img/2019/61c_class0.jpg
- image_path: /assets/img/2019/61c_class1.jpg
- image_path: /assets/img/2019/61c_class2.jpg
- image_path: /assets/img/2019/61c_class3.jpg
- image_path: /assets/img/2019/61c_class4.jpg
- image_path: /assets/img/2019/61c_class5.jpg
- image_path: /assets/img/2019/61c_class6.jpg
---
This was easily one of my favorite courses because it operates right at the intersection of EE and CS. I really liked the focus on hardware, performance, and how things are actually implemented in real life. Even more, I learned about a wealth of technical challenges and solutions that I didnt know much about before. Keeping in line with my love of embedded systems type projects, I was ecstatic at finally getting to learn C, RISC-V assembly, GDB, and Valgrind. In reality, the course focused more on the big ideas side and the coding part was mostly self-taught, but it was awesome nevertheless. Anyways, heres a couple of projects we did.
## Mandelbrot
{% include gallery %}
We generated pretty mathematical images using C. This project served as a nice dive into C and memory management. Overall, it was a very straightforward project and I really liked how I felt that I knew almost exactly what the computer was doing behind the scenes.
After we learned about OpenMP and SIMD, we had a lab on vastly improving the performance of Mandelbrot because its an “embarrassingly parallel” task. To simplify things, we only had to determine if a point was in the set or not. I ended up getting a 31x speedup over the serial version, which really opened my eyes to how much multithreading and other parallel techniques can improve performance.
## CS61Classify
{% include gallery id="gallery2" %}
Our next project was to implement an Artificial Neural Net (ANN) to identify numbers from the MNIST dataset. This definitely sounds more impressive than it actually was. All we did was write a couple functions to do dot products and matrix multiplication. The details of training and running the actual neural net were all handled for us. The real challenge was doing it all in RISC-V assembly. It was quite fun and gave me a better understanding of how a higher level language like C can get directly translated into machine code.
## CPU
{% include figure image_path="/assets/img/2019/61c_cpu.jpg" %}
Last but not least, we implemented the logic for a RISC-V processor in Logisim. We made everything from the ALU to the immediate generator to the control logic. When it came time to put it all together, I started by organizing all the parts into the same format as the picture of the data path from lecture. Keeping everything neat, organized, and aesthetic is kind of my thing. Then I added everything else.
One interesting part of the project was the extra credit for the ALU. We had to implement the mulh instruction which gets the upper 32 bits from multiplying two 32 bit numbers. Theres no built-in Logisim block for this, so I did some algebra to figure out how to do it. A bit messy, but it worked perfectly.
The most tedious part of the project was the control logic. We had to provide the correct control signals for each part of the data path to support each instruction. I started by making a spreadsheet for each instruction and the control signals necessary. Then I spent a good 6 hours looking at each and every control signal and what parts of the inputs determine them. The number of times I said “uniquely determine” is countless. As far as I know, it was a slightly unorthodox approach, but very compact and clean. Well worth the headache.

View File

@ -0,0 +1,62 @@
---
title: CS170 Final Project
date: 2019-12-12
categories: school
excerpt: The thrilling final project for CS170 tasked us with finding the best algorithm for approximating the optimal solution for an NP-hard problem.
header:
teaser: /assets/img/2019/170_graph.png
---
As the finale to an amazing algorithms course, we had to tackle a problem called Drive the TAs Home. It is setup as starting at a certain node in a graph with a certain number of TAs which all live in unique nodes on the graph. The goal is to find a cycle of nodes to travel through and a list of drop offs that minimizes energy cost. Dropping a TA off at a node makes them travel the shortest path to their home, with an energy cost of 1 per unit distance traveled. Driving along an edge has an energy cost of 2/3 per unit distance traveled. We werent looking for an exact algorithm but instead the best approximation we could.
Since the project changes every semester, I made our repo public, which you can find [here](https://github.com/dragonlock2/RaoTA).
## Algorithms
My teammates and I came up with quite a few algorithms in our search for the best outputs to the 949 inputs we were given. We also iterated many times and improved performance a lot along the way. Heres descriptions of our algorithms, in no particular order. In the interest of time, Ill keep them short.
### Brute Force (brutepython, brutecppLVIII, brutecppCC)
In order to provide a baseline we could compare our other algorithms against, I started by creating a brute force algorithm. To ensure we were finding optimal solutions, I used an object oriented approach with a Car object that has both a location and a set of TAs. We start with a Car at the starting location that has all the TAs. Then I used Dijkstras algorithm to search for the path of smallest energy cost to a Car at the starting location with no TAs. Conceptually, the “neighbors” of each Car involve all the possible nodes it can travel to and all the possible combinations of TAs it can drop off. The “cost” of the edge to that “neighbor” is just the cost of the drop offs and the cost to travel to that next node.
Improving performance of the algorithm was quite interesting. After optimizing the initial Python implementation as much as possible, I decided to convert it to C++. Based off some rough calculations, I reasoned that it would be barely possible to brute force the smallest size inputs we would be given, 50 nodes and 25 TAs. It took a lot of effort, a complete restart, and serious optimizations including bit manipulation and memory allocation, but I learned a lot and achieved a 100x speedup over the Python implementation. After using cProfile and Callgrind, I found that both my Python and C++ implementations probably couldnt be improved much further, so I moved onto the rest of the project.
{% include figure image_path="/assets/img/2019/170_callgrind.jpg" %}
### Sorted (sortedpython)
Even with the optimized brute force algorithm, it was still not fast enough to do anything above 16 TAs. As a first attempt at improving speed, to generate neighbors I tried sorting TAs by distance from their home and only dropping off farther TAs if I dropped off closer ones too. While an improvement over the naive solution of dropping everyone off immediately, this did not end up working too well.
### Minor Improvement (minorimprove)
Thinking about the optimal solution, I reasoned that no edge is double traveled by TAs on their ways home. Also, theres probably room to improve the cycle traveled to get to each drop off point using a TSP approximation. Based on these two observations, I wrote an algorithm that takes an existing output and improves it. However, it does rely on having a very good one already. Also, since I used Google OR-Tools there were cases where it did perform worse.
### Optimized TSP (optimizedtsp, optitsp)
My teammate Joe came up with this algorithm. Its based off the observation that dropping TAs off at their homes and using TSP to find a cycle actually works pretty well. First, he used LocalSolvers TSP solver to find an order to drop off TAs in. To optimize further, for each TA, hed consider all other nodes as drop off points and use the one with minimum cost. Repeating this multiple times ended getting very close to optimal for a lot of cases.
As we were working on our Semitree algorithm, I rewrote this algorithm as a subroutine. Since I didnt want to wait a day to get a LocalSolver license, I used Google OR-Tools. Later on, I moved over to Gurobi which improved performance even more. I also added on the drop off cycle optimization from the minor improvement algorithm to further reduce cost.
### ILP Reduction (gurobilp)
Talking to a bunch of HKN people, I realized that all of them used an ILP reduction for their algorithms. It was then that I learned about Gurobi, an ILP solver thats among the best in the business. Hearing everyone keep talking about finding “provably optimal” solutions got me interested. Three nights before the deadline, I took a look at the TSP ILP reduction. A couple hours later, I had an ILP formulation.
Basically, like the TSP ILP reduction Id have a binary variable `e[i,j]` for each pair of nodes, but directed instead to simplify things. Theres also binary variables for each TA for each node, called `v[i,k]`. I also had indicator variables for if a node is a drop off point. For the constraints, I first had to make sure each TA is dropped off and only once. Then for each drop off point, make sure we pick one edge leaving and one edge entering it. My first reduction had a couple more variables and constraints, but with some help from my teammate Kevin we got rid of them and improved performance significantly.
### Semitree (semitreeTSP, semitreeILP)
My teammate Kevin came up with easily the best algorithm we had. He worked on his own implementation, but I also did my own using a different perspective of the algorithm, which Ill explain. Basically, were looking for nodes whose removal splits the graph into subgraphs, which are called articulation points. Were also looking for biconnected components, which result from removing articulation points. We generate a tree-like structure based on these points and components. From the starting location, we look at all the articulation points in each biconnected component its in. For each point, we look at its child subgraphs. If theres one TA total in them, then we replace the point with a fake TA. If theres more than one, then we replace the point with a fake TA, force a visit there, and recurse on it.
To find a solution for the resulting biconnected components, wed employ one of our other algorithms, mainly Optimized TSP and ILP Reduction, which I modified to support forced visits. After solving subgraphs, wed stitch together the different parts to generate the final output. This algorithm worked so well because it employed provably optimal techniques in a divide and conquer fashion to break down the problem.
## Generating Outputs
In order to streamline the process of generating outputs, I setup a framework of multiple scripts to automate tedious tasks. The main one was bigsolve.py which ran a specified algorithm on certain inputs. The real benefit was that it only wrote to the output folder if the algorithms solution was better than the existing one. This allowed us to quickly try different modifications and algorithms without worry.
Since we found out about Gurobi less than three days to the deadline, we really had to make the most of our time. In an unfortunate turn of events, I sent my gaming computer and some Ryzen processors I bought for Black Friday home to work on during winter break. Literally the only computers we had were my 2018 Macbook Pro, Joes 2016 Macbook Pro, and one of the Hive machines. Luckily, due to heavy optimizations in our algorithms and good organization we were able to generate “optimal” outputs for all but about 180 inputs.
As for the breakdown of how each algorithm did, about ~80 of them were solved optimally using my brute force C++ algorithm. A good ~700 of them were solved “optimally” using semitreeILP, which used the ILP reduction as a subsolver. The rest of them had very good approximations generated using semitreeTSP, which used Optimized TSP as a subsolver. In fact, semitreeTSP could generate outputs for all 949 inputs in under an hour and was within ~2% of optimal if not optimal in most cases.
## Conclusion
At the end of the day, I did not expect this project to have as much an impact on me as it did. True to my personality, I tackled it first and foremost as a software engineering problem. I setup a framework that made development and testing of the algorithms wed develop straightforward. Comparing against the brute forced optimal solution and naive solution helped guide our efforts and led to some discoveries that inspired our best algorithms. Later on, I dived into the theory side to help come up with even better algorithms. Although our team did end up getting 5th out of about 366 teams, I really appreciated how much I learned in the process. More than anything, I really could not have done it without my teammates.

View File

@ -0,0 +1,26 @@
---
title: MMSim
date: 2019-12-12
categories: projects school
excerpt: Just for fun, I wrote a simulator for the flood fill algorithm for the MicroMouse DeCal I helped teach this semester.
header:
teaser: /assets/img/2019/mmsim_0.png
---
Out of the blue, I decided to write a simulator in Python for the MicroMouse DeCal I helped teach this semester. Past semesters of MicroMouse never got around to doing the actual maze solving and I felt that part of the reason was not having a good explanation or reference implementation of the algorithm. Flood fill is the de facto standard when it comes to this thing so I decided to learn it and implement it. Due to all the power outages and midterms, we ended up not getting to maze solving yet again but well definitely do it next semester.
Heres a [link](https://github.com/dragonlock2/MMSim) to my repo.
## Maze Representation
First, I came up with a simple and efficient way of storing mazes. Since mazes are constructed as a bunch of square cells with walls placed between them, I looked into a Cartesian coordinate system. For each cell, we can have north, south, east, and/or west walls. We represent having a wall in that direction as having the corresponding bit be a 1. This will make it easier to convert to Arduino later. I then setup a bunch of code to help read maze files and display them.
## Flood Fill
The flood fill algorithm is conceptually pretty simple. It can be modeled as water flowing along the fastest path from highest to lowest elevation. As the robot moves through the maze, it reconstructs it in memory, which necessitates updating the “heights” of each cell. Theres lots of room for improvement in the future, but my algorithm currently only considers the Manhattan distance between cells and constantly recalculates all heights using BFS.
## Robot Representation
As for the robot, I used an object oriented approach, naming it Karel after the way I was taught Java in high school. I modeled Karel with the knowledge that the algorithm would eventually be moved over to C++ on the Arduino. As such, I made sure to write code as non-Pythonic as possible and to reduce memory usage. To start, Karel has a couple of sensors which can tell us if theres certain walls around us. It can also turn left, turn right, and move forward. With each movement, we gain new information about the maze and so update our reconstruction accordingly. Just having a couple of sensors and move methods is all that flood fill needs to find the shortest path to the target.
{% include figure image_path="/assets/img/2019/mmsim_1.png" %}

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
assets/img/2019/61c_cpu.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
assets/img/2019/mmsim_0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
assets/img/2019/mmsim_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
assets/img/2019/phpinfo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
assets/img/2019/wp_test.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB