cmc/cleberg.net
My personal web garden & blog.
clone: git clone https://gitbay.org/cmc/cleberg.net.git
main: content/blog/2021-03-30-vps-web-server.org · raw
1#+date: [2021-03-30 Tue 00:00:00]
2#+title: VPS Web Server: Get Off Shared Hosting
3#+description: How to set up a VPS and host your own website.
4#+slug: vps-web-server
5#+filetags: :linux:self-hosting:
6
7* Shared Hosting vs. VPS (Virtual Private Server)
8
9Choosing a place to host a website is one of the most confusing decisions for
10beginner web developers. Even for experienced web devs, choosing between
11different forms of web hosting can be a daunting choice.
12
13First, let's take a look at [[https://en.wikipedia.org/wiki/Shared_web_hosting_service][shared web hosting]]. Shared web hosting is a product
14where you are purchasing a small piece of a web server that is being shared
15between many websites. As a result, the cost of shared hosting is extremely low.
16You won't have access to the server itself, which means you can't install your
17own software on the server, such as Docker. Usually, you are simply allowed to
18connect your domains to the server, set up domain security, and other small
19utilities.
20
21In contrast, a [[https://en.wikipedia.org/wiki/Virtual_private_server][virtual private server]] (VPS) is a virtual machine that replicates
22the environment of having a dedicated server to yourself. You are able to
23control the virtual server's host names, base file system, package manager, etc.
24Another great upside of a VPS is that since it's virtual, the company providing
25the VPS can dynamically increase the disk size, RAM size, or number of CPUs at
26any time. However, the virtual server is still physically located on a server
27that is shared between multiple virtual servers.
28
29The choice between shared hosting and VPS mostly depends on your skill level
30with system administration. If you're comforting working on a server that is
31mostly left up to you (or you're willing to learn), then a VPS is usually a
32better option. However, shared hosting is a fantastic option for people who
33don't want to have to learn how to manage their server.
34
35* My Situation
36
37I had used shared hosting for approximately 5 years before trying my first VPS.
38I manage a homelab and have had success running a server and performing typical
39sysadmin duties, but I was still hesitant to get a VPS. One fear was that I
40always struggled to properly set up the networking part of a server - DNS and
41hostname configurations were not my friend.
42
43As a little bit of background, I originally used [[https://www.siteground.com][Siteground]] for my initially
44shared hosting and stayed on that platform for at least a year. However, the
45user interface (UI) was clunky, and I didn't like how they handled certain
46technical aspects, so I switched to [[https://www.namecheap.com][Namecheap]]. Namecheap was great because it is
47the service I primarily use for purchasing domain names, which made it
48incredibly easy to link them to my hosting service. However, it was still
49mediocre shared hosting, and Namecheap is notorious for not letting you use
50[[https://letsencrypt.org][Let's Encrypt]] to obtain free SSL (Secure Socket Layer)/TLS (Transport Layer
51Security) certificates; Namecheap wants to make you purchase certificates
52through their store.
53
54Finally, I settled down with [[https://www.iwebfusion.net][iWebFusion]] for about the last year of my shared
55hosting. This service was pretty great, came with free SSL/TLS, and I never had
56any complaints.
57
58However, I finally grew tired of not being able to install software on my own
59web server. I wanted to be able to try out things like [[https://postmill.xyz][Postmill]] or [[https://matrix.org][Matrix]]. This
60is possible with a VPS, so I decided to grab a new domain name to try it out.
61
62* Getting Started: Buying a VPS
63
64The first step to moving over to a VPS is (you guessed it): finding a VPS
65provider. For my VPSs, I use [[https://1984hosting.com][1984]] and prefer their services much more than any
66alternative, due to their location (Iceland), their [[https://1984hosting.com/GDPR/][privacy policy]], their
67respect for GDPR, and the ability to remain anonymous if you pay in Bitcoin or
68Monero.
69
70[[https://njal.la][Njalla]] is another good, privacy-oriented option for VPS services.
71
72You'll have to decide what specifications you want on your VPS. For me, I only
73build and deploy low-resource HTML, PHP, and Python websites. This means I can
74survive on the smallest VPS: 1 CPU, 1GB of RAM, and 25GB SSD for $5.00 per
75month.
76
77As noted above, the great thing about a VPS is you can request your provider to
78increase the resources at any time.
79
80* Configuring DNS Settings
81
82Okay, so now let's get into some actual work that has to be done to get content
83moved from a shared host to a VPS. At this point, I'm assuming you have a shared
84host with website content that you can still access, and you've purchased a new
85VPS and can SSH into that server.
86
87The first change is minor, but it should be done immediately in order to get
88things moving: DNS settings. Go to wherever your DNS settings are handled. If
89your shared host also managed your DNS settings, you'll need to first move that
90DNS over to your new VPS provider. For me, I route my DNS through [[https://www.gandi.net][Gandi]].
91
92Once you know where your DNS settings are, go ahead and update the =A= records
93to match the public IP address of your VPS. For example:
94
95#+begin_src txt
96A example.com xxx.xxx.xxx.xxx
97A subdomain xxx.xxx.xxx.xxx
98CNAME www example.com.
99#+end_src
100
101If you have any other records that require updates, such as MX or TXT records
102for a mail server, be sure to update those accordingly. Personally, I don't host
103my own mail server. I route all mail on my custom domains to [[https://www.migadu.com][Migadu]]. Hosting
104your own email server can become complex quickly and is not for beginners.
105
106DNS changes can take up to 48 hours to propagate, so be sure to give it some
107time before assuming you've made an error.
108
109* Server Updates and Packages
110
111Now that the DNS settings have been changed, let's set up our server while we
112wait for the DNS to propagate. First up is to ssh into your server. If you've
113signed up with a service like DigitalOcean, you can add your SSH key to your
114account and to your VPS droplet so that you don't need a password in order to
115SSH.
116
117#+begin_src sh
118ssh root@xxx.xxx.xxx.xxx
119#+end_src
120
121The VPS that is used in this blog post runs Ubuntu 20.04 with an Apache web
122server. If you're working on a different operating system (OS) or want a
123different web server, such as Nginx, you'll have to use different commands to
124set it up.
125
126First, let's update and upgrade our server.
127
128*NOTE:* Since we have logged in to the server as =root= for now, we don't need
129to use the =sudo= modifier before our commands.
130
131#+begin_src sh
132apt update && apt upgrade -y
133#+end_src
134
135* Create A User Account
136
137While being able to use =root= can be beneficial at times, you shouldn't use
138=root= unless you have to.
139
140So let's set up a new user in our system. The =-m= option below tells the OS to
141create a home directory for the new user.
142
143#+begin_src sh
144adduser USERNAME
145#+end_src
146
147Now, create a password for that user.
148
149#+begin_src sh
150passwd USERNAME
151#+end_src
152
153Finally, add the user to the sudoers file, so they can perform privileged
154commands.
155
156#+begin_src sh
157usermod -a -G sudo USERNAME
158#+end_src
159
160If you are using SSH (secure shell protocol) keys and not passwords, you'll need
161to copy your SSH key from your local machine to the VPS. If you haven't disabled
162password-based SSH yet, the easiest way to do this is =ssh-copy-id= from your
163local computer (not from the VPS):
164
165#+begin_src sh
166ssh-copy-id testuser@xxx.xxx.xxx.xxx
167#+end_src
168
169If you've disabled password-based SSH, you'll need to manually copy your SSH key
170into the =~/.ssh/authorized_keys= file.
171
172* Install Software
173
174Our goal here is to host a web server, so the next step is to install the Apache
175web server and any other packages we need.
176
177From this point on, I will be logged in as a user (not =root=) and will need to
178use the =sudo= modifier for most commands.
179
180#+begin_src sh
181sudo apt update; sudo apt upgrade -y; sudo apt autoremove -y
182sudo apt install apache2
183#+end_src
184
185If you need other language support, such as PHP, you'll need to install that
186too.
187
188#+begin_src sh
189sudo apt install libapache2-mod-php php-dom
190sudo a2enmod php
191sudo systemctl restart apache2
192#+end_src
193
194* Website Files & Folders
195
196Next up is to create the directories for the domain(s) we want to be hosted on
197this web server.
198
199#+begin_src sh
200cd /var/www
201sudo mkdir example.com
202#+end_src
203
204We have a folder for =example.com= now, so let's add an =index.html= file and
205put it within a specific =public_html= folder. You don't need this =public_html=
206if you don't want it, but it helps with organizing items related to
207=example.com= that you don't want to publish to the internet.
208
209#+begin_src sh
210cd example.com
211sudo mkdir public_html && cd public_html
212sudo nano index.html
213#+end_src
214
215You can put anything you want in this =index.html= file. If you can't think of
216anything, paste this in there:
217
218#+begin_src html
219<!DOCTYPE html>
220<html lang="en">
221 <head>
222 <meta charset="utf-8" />
223 <meta name="viewport" content="width=device-width, initial-scale=1" />
224 <title>Hello, world!</title>
225 </head>
226 <body>
227 <h1>Hello, world!</h1>
228 </body>
229</html>
230#+end_src
231
232If you want something to be served at =example.com/page01/file.txt=, you'll have
233to create the =page01= directory under the =example.com= directory. For example:
234
235#+begin_src sh
236cd /var/www/example.com/public_html
237sudo mkdir page01
238sudo nano file.txt
239#+end_src
240
241* Apache Configuration
242
243Now, let's set up the files that will tell the server where to find the files
244for =example.com=. We will copy the default configuration file and create our
245own.
246
247#+begin_src sh
248cd /etc/apache2/sites-available
249sudo cp 000-default.conf example.com.conf
250sudo nano example.com.conf
251#+end_src
252
253This configuration file will have a few default lines, but you'll need to edit
254it to look similar to this (settings may change based on your personal needs):
255
256#+begin_src config
257<VirtualHost *:80>
258 ServerAdmin your-email@email-provider.com
259 ServerName example.com
260 ServerAlias www.example.com
261 DocumentRoot /var/www/example.com/public_html
262 ErrorLog ${APACHE_LOG_DIR}/error.log
263 CustomLog ${APACHE_LOG_DIR}/access.log combined
264</VirtualHost>
265#+end_src
266
267Now, enable the configuration for your new site, disable the default
268configuration, and reload the web server.
269
270#+begin_src sh
271sudo a2ensite example.com.conf
272sudo a2dissite 000-default.conf
273sudo systemctl reload apache2
274#+end_src
275
276You can always run a test to make sure no errors or warnings are found in your
277configuration files.
278
279#+begin_src sh
280sudo apache2ctl configtest
281#+end_src
282
283Now, restart the web server entirely. After this, you should be able to browse
284to =http://example.com= and see the HTML (hypertext markup language) content you
285provided earlier. Note that SSL/TLS has not been enabled yet, so you won't be
286able to use the secure version yet (=https://example.com=).
287
288#+begin_src sh
289sudo systemctl restart apache2
290#+end_src
291
292You can repeat this for as many websites as you need. Just create the domain
293folders in =/var/www/=, add the configuration file, enable the configuration,
294and restart =apache2=.
295
296* SSL/TLS Certificates: Serve Websites Over HTTPS
297
298In order to serve secure content, you'll need to obtain SSL/TLS certificates.
299Luckily, there's a free tool called [[https://certbot.eff.org][Certbot]] that helps us with the process.
300
301The first step is to install =snapd= and =core= for Ubuntu.
302
303#+begin_src sh
304sudo apt install snapd
305sudo snap install core
306sudo snap refresh core
307#+end_src
308
309Next, install the =certbot= snap package.
310
311#+begin_src sh
312sudo snap install --classic certbot
313#+end_src
314
315Execute the following command to ensure that the =certbot= command can
316be run.
317
318#+begin_src sh
319sudo ln -s /snap/bin/certbot /usr/bin/certbot
320#+end_src
321
322Finally, you can run =certbot= one of two ways:
323
3241. run it and let it alter your Apache configuration files automatically to
325 enable HTTPS (Hypertext Transport Protocol) redirects.
3262. run it and only allow it to create certificates. You'll need to manually
327 alter the config files to enable HTTPS redirects.
328
329Run certbot and allow automatic config changes:
330
331#+begin_src sh
332sudo certbot --apache
333#+end_src
334
335Run certbot for certificates only and don't allow it to alter config
336files:
337
338#+begin_src sh
339sudo certbot certonly --apache
340#+end_src
341
342The Certbot packages on your system come with a =cron= job or =systemd= timer
343that will renew your certificates automatically before they expire. You will not
344need to run Certbot again unless you change your configuration. You can test
345automatic renewal for your certificates by running this command:
346
347#+begin_src sh
348sudo certbot renew --dry-run
349#+end_src
350
351Now, test your domains by going to =https://example.com=.
352
353* Firewall Security
354
355To enable better security on your server, you'll need to enable a basic
356firewall. For Ubuntu, we'll use [[https://cleberg.net/blog/ufw.html][the uncomplicated firewall]].
357
358Now, add the following rules to the firewall allow SSH, Apache, and HTTP(S)
359connections. If you need to, you can enable different ports for specific
360applications.
361
362#+begin_src sh
363sudo ufw default deny incoming
364sudo ufw default allow outgoing
365sudo ufw allow OpenSSH
366sudo ufw allow Apache
367sudo ufw allow proto tcp from any to any port 80,443
368#+end_src
369
370Once you've added all the rules you need, enable the firewall.
371
372#+begin_src sh
373sudo ufw enable
374#+end_src
375
376* Troubleshooting
377
378If you run into any issues during your VPS set-up, be sure to walk back through
379your actions and make sure you didn't miss any steps.
380
381Many websites have fantastic guides to setting up various web servers. This is
382one of the areas [[https://www.digitalocean.com/community/tutorials][where DigitalOcean shines]]. For simpler or more Linux-oriented
383questions, I suggest using [Linuxize] ([[https://linuxize.com]]).
384
385If you're getting certain errors (e.g. =500 Internal Server Error=) and need to
386debug locally, you can view the =access.log= and =error.log= files in the
387=/var/log/apache/= directory.