How to set up a webserver on Raspberry Pi Zero W A Raspberry Pi Zero W is a dirt cheap way to build your own personal webserver for less than $30. It is the least powerful version of the Raspberry Pi but it's more than enough power for personal use with not many users. If you are expecting more people, you can also follow these instructions to set up the same webserver but stick it in a Raspberry Pi 3 and it'll give you a lot more power. You'll also need your network to be wifi enabled. 1. Buy the hardware. - Raspberry Pi Zero W Board - Case (if desired) - A 16 GB Class 4 micro SD card with an adapter to plug into your computer either via SD card slot or USB. Why class 4? Class 4s have a fast read speed, class 10 have a fast write speed. If you're using a webserver that primarily exists to display data, you want the card that does a better job reading. Bonus, they're cheap. - A 1 amp micro USB charger (for power). If you're using a Raspberry Pi 3, you'll want a 2.5 amp power supply. 2. Download the software. - The Raspbian Stretch Lite image - this is the operating system for the pi that you'll install on the micro SD card. When you download this, it'll be in a .zip format. You need to extract the .img file within it in order for balenaetcher to use it. You can download the file here: https://www.raspberrypi.org/downloads/raspbian/ - balenaetcher (install on your PC) - this will be used to put the Raspbian image on the SD card. You can download the etcher from here: https://www.balena.io/etcher/ - putty (install on your PC) - this will be used to issue all of the commands to the pi remotely (from your PC). You can download putty here: https://www.putty.org/ 3. Put the SD card in your computer via the adapter and quick format it to FAT32. 4. Use balenaetcher to write the Raspbian Stretch Lite image to your SD card. If you have trouble with this step, check out this page: https://www.raspberrypi.org/documentation/installation/installing-images/README.md Because the Raspberry Pi Zero W uses micro OTG USB ports and a micro HDMI port, you probably don't have an easy way to hook it up and set it up. So the rest of this guide will show you how to do it via putty. In the end, you shouldn't need to input anything directly, you'll do it via your other computer from putty. 5. Setup wifi on the pi: while the SD card is still in your computer, create a blank text file in the root folder and name it: wpa_supplicant.conf open it with notepad and paste this text (modify for your network name and password) and then save it. ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev network={ ssid="YOUR_NETWORK_NAME" psk="YOUR_PASSWORD" key_mgmt=WPA-PSK } 6. While the SD card is still in your computer, in the root folder of it, create a blank file and name it JUST: ssh Your computer will probably try to rename it ssh.txt or something similar, just remove the .txt. We need ssh enabled in order for the pi to allow putty to talk to it. Raspbian ships with ssh disabled by default, but by sticking this file on the SD card, it tells it to turn it on. It should be an empty file that is only named: ssh 7. Now take the SD card out of your computer, put it in the Raspberry Pi and boot it up for the first time (put the SD card in and then plug it into the power adapter and it'll boot up automatically). 8. Open putty and try to connect to hostname: raspberrypi (on port 22). 9. If you get a login prompt, hooray! The login username is pi and the password is raspberry, go ahead and log in. Before your proceed, you should know that you can send text to the pi via putty by copying and pasting. If you copy something (like from this guide) from your PC using ctrl-C, within putty, if you right click on the putty screen, it'll send what's in your clipboard to the pi (you'll probably need to then press enter). You should also know why some of the commands below require you to type sudo first and some don't. Raspbian is based on Debian Linux, and Linux is very conservative when it comes to regular and super users, and some commands need you to be a super user (root) to execute. Sudo is a way to pretend to be root. Basically it's a way to force you to think about what you're doing by making you type sudo first. 10. It's probably a good idea to change your password at this point because everybody knows the default password for a raspberry pi is raspberry. To do this, issue command: passwd You'll be asked to enter your existing password (raspberry) and enter your new password. 11. Now you probably want to set a static IP address because your router will need it in order to send traffic to it. If you don't do this step, eventually the IP address of the pi could change and you won't be able to connect to it unless you change it to the new IP address. It's easiest just to always know what IP address the pi is on. Do the following command: sudo nano /etc/dhcpcd.conf Scroll down and put this text at the bottom. This will set it up for IP 150 on a network of 192.168.0.X. You may need to modify this if your network is different! You should match the IP numbering of your router (which is probably at X.X.X.1, the X.X.X for the pi should match the router): interface wlan0 static ip_address=192.168.0.150/24 static routers=192.168.0.1 static domain_name_servers=192.168.0.1 Press CTRL-X, and choose to save it when you are prompted. 12. Reboot the pi so we can make sure the static IP address works. Do: sudo reboot Putty will crash, give it a minute, then re-open putty and try to connect, but this time try to connect to 192.168.0.150 (or whatever IP you used). You should also save this connection in putty, you may use it frequently. Remember the username is still pi but you changed the password in the previous step, so use your new password. 13. You need to create a username/password for sharing files across the network, let's say I want to use username: dad and password: isawesome (you should modify this to suit your needs). You do that by issuing these commands: sudo useradd dad sudo passwd dad (you will be prompted to enter the password twice, so enter isawesome both times) 14. Now you need to install some software. I prefer to do these one at a time, so go in this order. Each time it will do some stuff then prompt you for a y/n, hit Y and let it do its thing. You must be connected to the internet for this to work. sudo apt-get update sudo apt-get install apache2 sudo apt-get install mysql-server sudo apt-get install php sudo apt-get install php-mysql sudo apt-get install samba (if you are curious what you are adding here, apache2 is the apache web server, this needs to be running to display files to your website to visitors, mysql-server is a database server that is handy for when you want to write web applications that store information, php is a way to make a dynamic page that uses logic to show different output to your users, it's a little old but it's still ridiculously fast, so I still use it, php-mysql is an interface you'll need to allow php to talk to mysql, and lastly samba is a way for you to connect your PC computer to the pi (using a mapped network drive) to be able to edit files directly on the webserver using a familiar interface rather than having to use something like putty) 15. Now you need to allow samba to share the www folder so you can copy files into it, do the following: (note where it says dad, that's the user you added above) sudo nano /etc/samba/smb.conf At the end of the file, enter text: [webserver] path = /var/www/html valid users = dad browseable = yes writeable = yes CTRL-X to exit and save the file when prompted. 16. Now you need to add the user you created before (dad) to samba by doing: sudo smbpasswd -a dad 17. Now for good measure let's restart samba: sudo service smbd restart 18. You should be able to now go into your PC, right click on My Computer, and map a network drive to: \\192.168.0.150\webserver You will choose "other credentials" and the username is: dad, the password is: isawesome, click on the box to remember the connection so it'll be available when you restart your computer. It should connect to the pi, but you'll get an error if you try to write files to it, so now we need to change the owner of that directory. 19. Back in putty, do this: cd / cd var cd www sudo chown dad:dad html NOTE - if you are creating web applications that will write files to your webserver, this step will cause that not to work because the webserver is going to run the operation as root, but you just changed the owner of the /var/www/html folder to be the user that you created for the samba share. This step as necessary to give you read/write access over the shared/mapped network drive but broke your webserver's ability to write to its own html directory. This can probably be done many different ways, but what I prefer to do is ONLY allow write access on the files or folders that I explicitly allow. This just seems safer, security-wise, rather than leave the entire webserver open to read/write. To do that, you can use chmod to change the permissions for a specific file or specific directory only. To do that, you do: cd / cd var cd www cd html sudo chmod 777 myfile.dat sudo chmod 777 images This will allow only the myfile.dat file in the html (root) directory to be written to by the webserver. Likewise, if "images" in my example here is a directory, it will allow your webserver to write to that directory. If you have directory within directory or files within directory that you want to apply the chmod to all within it, you can use the -R switch. But I'm not going to tell you exactly how to write that because I want you to think about it first. :-) 20. Now you need to choose a username and password for mysql if you're going to be doing database stuff. I like to make this easy, let's call it username: myapp, password: myapp, database: myapp Go into mysql: sudo mysql Now within mysql, issue these commands one by one, you must include the ; at the end of them: CREATE USER 'myapp'@'%' IDENTIFIED BY 'myapp'; CREATE DATABASE myapp; USE myapp; GRANT ALL ON myapp.* TO 'myapp'@'%'; FLUSH PRIVILEGES; Now when you use database calls within your webserver application, you can connect to the database where username/password/database are all: myapp (feel free to modify if you don't think that's secure enough). You can quit mysql by typing quit; 21. In your router, set up port forwarding for port 80 to 192.168.0.150, or whatever IP you set your pi to be. I can't give you instructions on this because it'll vary from router to router. You'll probably need to go into your web browser and visit site 192.168.0.1, login with your admin username/password and set up a rule in port forwarding. Congrats, you now have a fully functioning webserver! You may wish to sign up with a ddns service where you can get a name like mywebsite.ddns.net that will point traffic going to that address to your pi. If you have a dyanmic ip address through your internet service provider (you probably do), you should download and install the ddns updater tool that your ddns service provides. This will continuously monitor your external IP address and update your ddns site record with it so if your ISP changes your IP, the traffic will continue going to the the right place. Lastly, if you ever need to shutdown or restart the pi, you shouldn't just unplug it, or pull the SD card. You should first login to the pi via putty and then issue this command to shut it down (give it a minute before you unplug it after this): sudo shutdown -h now If you want to restart it instead, just do: sudo reboot Any time you're done with putty, you can either just close it, or type exit and hit enter. The following is additional information you probably don't need, but I needed it so I'm including it. You may find this useful in the future. 22. You may wish to setup cron jobs, these are "scheduled tasks" that you can setup to do something at a specific time. They can run daily, by the minute, once a week, etc. Before you do anything with cron, I strongly suggest you save a file with your crontab entries somewhere else as a backup. Cron makes it ridiculously easy to delete your scheduled tasks with NO PROMPT! This really seems like an oversight by the people who wrote cron. I've lost my cron entries by using the wrong switch and it doesn't even ask you if you're sure before deleting them! To open the list of your cron(s), run: sudo crontab -e NOTE - the first time you do this in Raspbian, it'll ask you what editor you want. I like #2 (nano). Just press 2 to select it. At the bottom of the file you will need to specify your jobs in a specific format: minute(0-59) hour(0-23) dayofmonth(1-31) month(1-12) dayofweek(0-6,sun-to-sat) command A * means "any". So if you want to run program "xyz" on the first day of every month at midnight, you could do: 0 0 1 * * xyz One way I use it is by scheduling SQL statements to be inserted into the mysql database like such: 0 0 * * 5 mysql -umyapp -pmyapp myapp -e "insert into mytable (person, amount, date) values ('me', 5, NOW());" Another thing you could do is automatically dump a table out of mysql every day at a specific time: 0 0 * * * echo "select * from mytable" | mysql -umyapp -pmyapp myapp > /var/www/html/dump/mytable.dat Why would I do this? Because I have a daily backup job run by another computer to go out to my webserver and backup every file that's out there. By dumping my mysql tables into files every night, and by backing up the webserver every night, I always have a backup of my mysql table in case something happens. It's inherently risky because if someone knows the directory and filename of the file you're dumping mysql into, they can open it up and view the entire contents of your table. This would be a very bad practice if you were housing sensitive information like user info or financial information, so don't do that. 23. However, if you're not housing sensitive information, you can make your webserver slightly more secure by using redirects on folders. Any time you visit a website, the webserver looks for some default filenames to try and display it to you. It tries index.htm, index.html, and sometimes index.php, etc. But if there are no files of those names in that folder, you just see an output of every file in that directory. This is risky because someone can just look at any file, they don't have to know the name of it. This can be disabled, but by default, it is NOT disabled in apache2. I actually have several reasons to need directory listing view, so I don't want to disable it. But I can make it a little more secure by including a file in every directory and subdirectory on my webserver that I don't want someone snooping in. Simply create a file named index.html and within it, paste this: This will automatically redirect anybody who tries to visit that directory on your webserver back to the main webpage. They won't be able to snoop to see what's in the directory. It won't show them any files and it will immediately "kick them out". So let's say I create a subdirectory in my webserver called dbdump. By including this index.html file in the dbdump subdirectory, someone trying to snoop to see what exactly is in my dbdump directory will be immediately kicked out. Caution - if they know the directory name and the file name, you can't stop them, they'll be able to view it. So if you're following my instructions, you should definitely name something unique and not what I've used ("dbdump" or "mytable.dat") to lessen the chances of someone finding it. 24. Dump any database When I need to move a database from one webserver to another, you can't just pick up the mysql data and move it, unless you dump it first using mysqldump. This is inherently risky, though, because you'll be dumping out the entire contents of the database to a publicly readable place. You should probably disconnect your internet while you do this part. This is how you can do this on the Raspberry Pi Zero, e.g. if you are moving from one server to another: cd / cd var cd www cd html sudo mkdir dbdump sudo chmod 777 dbdump cd dbdump mysqldump -umyapp -pmyapp --all-databases > all_db_backup.sql After you are done (with the next step), you should probably delete the entire thing: sudo rm all_db_backup.sql sudo rm index.html (if you had created one of those redirect kicker outer things) cd .. sudo rmdir dbdump 25. After you dump the all_db_backup.sql file in the previous step AND have moved it to your new webserver, you can import it into your new webserver's mysql. First navigate to the directory where you put it, I'll assume you put it in the new web server at /var/www/html/dbdump: cd / cd var cd www cd html cd dbump Then you can import it with this command. If it asks you for a password, just hit enter: sudo mysql -u root -p < all_db_backup.sql Again, it's going to be a good idea to remove the all_db_backup.sql file after you've verified that all of your data is where it needs to be. Just do: sudo rm all_db_backup.sql 26. Misc packages you may need to install using sudo apt-get install: - php-gd (this contains image resizing routines that you may need)