aboutsummaryrefslogtreecommitdiff
path: root/content/blog/2021-03-30-vps-web-server.org
blob: 4992009be326a153797a25a1ec2c36fb36cb39aa (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
#+date: <2021-03-30 Tue 00:00:00>
#+title: Ultimate Guide to Setting Up Your Own VPS Web Server
#+description: Step-by-step tutorial on how to configure and manage a VPS web server for reliable, secure, and scalable website hosting.
#+slug: vps-web-server

* Shared Hosting vs. VPS

Choosing a place to host a website is one of the most confusing
decisions for beginner web developers. Even for experienced web devs,
choosing between different forms of web hosting can be a daunting
choice.

First, let's take a look at
[[https://en.wikipedia.org/wiki/Shared_web_hosting_service][shared web
hosting]]. Shared web hosting is a product where you are purchasing a
small piece of a web server that is being shared between many websites.
As a result, the cost of shared hosting is extremely low. You won't have
access to the server itself, which means you can't install your own
software on the server, such as Docker. Usually, you are simply allowed
to connect your domains to the server, set up domain security, and other
small utilities.

In contrast, a
[[https://en.wikipedia.org/wiki/Virtual_private_server][virtual private
server]] (VPS) is a virtual machine that replicates the environment of
having a dedicated server to yourself. You are able to control the
virtual server's host names, base file system, package manager, etc.
Another great upside of a VPS is that since it's virtual, the company
providing the VPS can dynamically increase the disk size, RAM size, or
number of CPUs at any time. However, the virtual server is still
physically located on a server that is shared between multiple virtual
servers.

The choice between shared hosting and VPS mostly depends on your skill
level with system administration. If you're comforting working on a
server that is mostly left up to you (or you're willing to learn), then
a VPS is usually a better option. However, shared hosting is a fantastic
option for people who don't want to have to learn how to manage their
server.

* My Situation

I had used shared hosting for approximately 5 years before trying my
first VPS. I manage a homelab and have had success running a server and
performing typical sysadmin duties, but I was still hesitant to get a
VPS. One fear was that I always struggled to properly set up the
networking part of a server - DNS and hostname configurations were not
my friend.

As a little bit of background, I originally used
[[https://www.siteground.com][Siteground]] for my initially shared
hosting and stayed on that platform for at least a year. However, the UI
was clunky, and I didn't like how they handled certain technical
aspects, so I switched to [[https://www.namecheap.com][Namecheap]].
Namecheap was great because it is the service I primarily use for
purchasing domain names, which made it incredibly easy to link them to
my hosting service. However, it was still mediocre shared hosting, and
Namecheap is notorious for not letting you use
[[https://letsencrypt.org][Let's Encrypt]] to obtain free SSL/TLS
certificates; Namecheap wants to make you purchase certificates through
their store.

Finally, I settled down with [[https://www.iwebfusion.net][iWebFusion]]
for about the last year of my shared hosting. This service was pretty
great, came with free SSL/TLS, and I never had any complaints.

However, I finally grew tired of not being able to install software on
my own web server. I wanted to be able to try out things like
[[https://postmill.xyz][Postmill]] or [[https://matrix.org][Matrix]].
This is possible with a VPS, so I decided to grab a new domain name to
try it out.

* Getting Started: Buying a VPS

The first step to moving over to a VPS is (you guessed it): finding a
VPS provider. For my VPSs, I use [[https://1984hosting.com][1984]] and
prefer their services much more than any alternative, due to their
location (Iceland), their [[https://1984hosting.com/GDPR/][privacy
policy]], their respect for GDPR, and the ability to remain anonymous if
you pay in Bitcoin or Monero.

[[https://njal.la][Njalla]] is another good, privacy-oriented option for
VPS services.

You'll have to decide what specifications you want on your VPS. For me,
I only build and deploy low-resource HTML, PHP, and Python websites.
This means I can survive on the smallest VPS: 1 CPU, 1GB of RAM, and
25GB SSD for $5.00 per month.

As noted above, the great thing about a VPS is you can request your
provider to increase the resources at any time.

* Configuring DNS Settings

Okay, so now let's get into some actual work that has to be done to get
content moved from a shared host to a VPS. At this point, I'm assuming
you have a shared host with website content that you can still access,
and you've purchased a new VPS and can SSH into that server.

The first change is minor, but it should be done immediately in order to
get things moving: DNS settings. Go to wherever your DNS settings are
handled. If your shared host also managed your DNS settings, you'll need
to first move that DNS over to your new VPS provider. For me, I route my
DNS through [[https://www.gandi.net][Gandi]].

Once you know where your DNS settings are, go ahead and update the =A=
records to match the public IP address of your VPS. For example:

#+begin_src txt
A         example.com     xxx.xxx.xxx.xxx
A         subdomain       xxx.xxx.xxx.xxx
CNAME     www             example.com.
#+end_src

If you have any other records that require updates, such as MX or TXT
records for a mail server, be sure to update those accordingly.
Personally, I don't host my own mail server. I route all mail on my
custom domains to [[https://www.migadu.com][Migadu]]. Hosting your own
email server can become complex quickly and is not for beginners.

DNS changes can take up to 48 hours to propagate, so be sure to give it
some time before assuming you've made an error.

* Server Updates and Packages

Now that the DNS settings have been changed, let's set up our server
while we wait for the DNS to propagate. First up is to ssh into your
server. If you've signed up with a service like DigitalOcean, you can
add your SSH key to your account and to your VPS droplet so that you
don't need a password in order to SSH.

#+begin_src sh
ssh root@xxx.xxx.xxx.xxx
#+end_src

The VPS that is used in this blog post runs Ubuntu 20.04 with an Apache
web server. If you're working on a different operating system (OS) or
want a different web server, such as Nginx, you'll have to use different
commands to set it up.

First, let's update and upgrade our server.

*NOTE:* Since we have logged in to the server as =root= for now, we
don't need to use the =sudo= modifier before our commands.

#+begin_src sh
apt update && apt upgrade -y
#+end_src

* Create A User Account

While being able to use =root= can be beneficial at times, you shouldn't
use =root= unless you have to.

So let's set up a new user in our system. The =-m= option below tells
the OS to create a home directory for the new user.

#+begin_src sh
adduser USERNAME
#+end_src

Now, create a password for that user.

#+begin_src sh
passwd USERNAME
#+end_src

Finally, add the user to the sudoers file, so they can perform
priveleged commands.

#+begin_src sh
usermod -a -G sudo USERNAME
#+end_src

If you are using SSH keys and not passwords, you'll need to copy your
SSH key from your local machine to the VPS. If you haven't disabled
password-based SSH yet, the easiest way to do this is =ssh-copy-id= from
your local computer (not from the VPS):

#+begin_src sh
ssh-copy-id testuser@xxx.xxx.xxx.xxx
#+end_src

If you've disabled password-based SSH, you'll need to manually copy your
SSH key into the =~/.ssh/authorized_keys= file.

* Install Software

Our goal here is to host a web server, so the next step is to install
the Apache web server and any other packages we need.

From this point on, I will be logged in as a user (not =root=) and will
need to use the =sudo= modifier for most commands.

#+begin_src sh
sudo apt update; sudo apt upgrade -y; sudo apt autoremove -y
sudo apt install apache2
#+end_src

If you need other language support, such as PHP, you'll need to install
that too.

#+begin_src sh
sudo apt install libapache2-mod-php php-dom
sudo a2enmod php
sudo systemctl restart apache2
#+end_src

* Website Files & Folders

Next up is to create the directories for the domain(s) we want to be
hosted on this web server.

#+begin_src sh
cd /var/www
sudo mkdir example.com
#+end_src

We have a folder for =example.com= now, so let's add an =index.html=
file and put it within a specific =public_html= folder. You don't need
this =public_html= if you don't want it, but it helps with organizing
items related to =example.com= that you don't want to publish to the
internet.

#+begin_src sh
cd example.com
sudo mkdir public_html && cd public_html
sudo nano index.html
#+end_src

You can put anything you want in this =index.html= file. If you can't
think of anything, paste this in there:

#+begin_src html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>Hello, world!</title>
    </head>
    <body>
        <h1>Hello, world!</h1>
    </body>
</html>
#+end_src

If you want something to be served at =example.com/page01/file.txt=,
you'll have to create the =page01= directory under the =example.com=
directory. For example:

#+begin_src sh
cd /var/www/example.com/public_html
sudo mkdir page01
sudo nano file.txt
#+end_src

* Apache Configuration

Now, let's set up the files that will tell the server where to find the
files for =example.com=. We will copy the default configuration file and
create our own.

#+begin_src sh
cd /etc/apache2/sites-available
sudo cp 000-default.conf example.com.conf
sudo nano example.com.conf
#+end_src

This configuration file will have a few default lines, but you'll need
to edit it to look similar to this (settings may change based on your
personal needs):

#+begin_src config
<VirtualHost *:80>
    ServerAdmin your-email@email-provider.com
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com/public_html
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
#+end_src

Now, enable the configuration for your new site, disable the default
configuration, and reload the web server.

#+begin_src sh
sudo a2ensite example.com.conf
sudo a2dissite 000-default.conf
sudo systemctl reload apache2
#+end_src

You can always run a test to make sure no errors or warnings are found
in your configuration files.

#+begin_src sh
sudo apache2ctl configtest
#+end_src

Now, restart the web server entirely. After this, you should be able to
browse to =http://example.com= and see the HTML content you provided
earlier. Note that SSL/TLS has not been enabled yet, so you won't be
able to use the secure version yet (=https://example.com=).

#+begin_src sh
sudo systemctl restart apache2
#+end_src

You can repeat this for as many websites as you need. Just create the
domain folders in =/var/www/=, add the configuration file, enable the
configuration, and restart =apache2=.

* SSL/TLS Certificates: Serve Websites Over HTTPS

In order to serve secure content, you'll need to obtain SSL/TLS
certificates. Luckily, there's a free tool called
[[https://certbot.eff.org][Certbot]] that helps us with the process.

The first step is to install =snapd= and =core= for Ubuntu.

#+begin_src sh
sudo apt install snapd
sudo snap install core
sudo snap refresh core
#+end_src

Next, install the =certbot= snap package.

#+begin_src sh
sudo snap install --classic certbot
#+end_src

Execute the following command to ensure that the =certbot= command can
be run.

#+begin_src sh
sudo ln -s /snap/bin/certbot /usr/bin/certbot
#+end_src

Finally, you can run =certbot= one of two ways:

1. run it and let it alter your Apache configuration files automatically
   to enable HTTPS redirects.
2. run it and only allow it to create certificates. You'll need to
   manually alter the config files to enable HTTPS redirects.

Run certbot and allow automatic config changes:

#+begin_src sh
sudo certbot --apache
#+end_src

Run certbot for certificates only and don't allow it to alter config
files:

#+begin_src sh
sudo certbot certonly --apache
#+end_src

The Certbot packages on your system come with a cron job or systemd
timer that will renew your certificates automatically before they
expire. You will not need to run Certbot again unless you change your
configuration. You can test automatic renewal for your certificates by
running this command:

#+begin_src sh
sudo certbot renew --dry-run
#+end_src

Now, test your domains by going to =https://example.com=.

* Firewall Security

To enable better security on your server, you'll need to enable a basic
firewall. For Ubuntu, we'll use
[[../secure-your-network-with-the-uncomplicated-firewall/][the
uncomplicated firewall]].

Now, add the following rules to the firewall allow SSH, Apache, and
HTTP(S) connections. If you need to, you can enable different ports for
specifics applications, SFTP, etc.

#+begin_src sh
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow Apache
sudo ufw allow proto tcp from any to any port 80,443
#+end_src

Once you've added all the rules you need, enable the firewall.

#+begin_src sh
sudo ufw enable
#+end_src

* Troubleshooting

If you run into any issues during your VPS set-up, be sure to walk back
through your actions and make sure you didn't miss any steps.

Many websites have fantastic guides to setting up various web servers.
This is one of the areas
[[https://www.digitalocean.com/community/tutorials][where DigitalOcean
shines]]. For simpler or more Linux-oriented questions, I suggest using
[Linuxize] ([[https://linuxize.com]]).

If you're getting certain errors (e.g. =500 Internal Server Error=) and
need to debug locally, you can view the =access.log= and =error.log=
files in the =/var/log/apache/= directory.