aboutsummaryrefslogtreecommitdiff
path: root/content/blog/2024-04-08-docker-local-web-server.org
blob: dd959c1d7e3912f6b28f71a82b818bd194247787 (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
#+date:        <2024-04-08 Mon 00:00:00>
#+title:       Local Web Dev Server Setup with Docker & Nginx
#+description: Instructions for setting up a local web development environment employing Docker Desktop and Nginx web server to facilitate development and testing workflows.
#+slug:        docker-local-web-server
#+filetags:    :docker:nginx:webserver:

When developing websites locally, I often use a simple Python web server to
observe the changes.

#+begin_src sh
python3 -m http.server
#+end_src

However, this approach has its limitations. For example, this approach does not
enable logging or access controls. You also need to customize =SimpleHTTPServer=
if you have advanced needs from your web server.

So, I went to find an alternative that is almost as easy and far more extensible
and found Docker Desktop to be a suitable replacement.

* Docker Desktop

** Installation

[[https://www.docker.com/products/docker-desktop/][Docker Desktop]] is a desktop GUI for the phenomenal Docker container software.
This allows you to manage containers, images, volumes, environments, and
extensions via an easy-to-use GUI.

To install, open the link above and click the =Download= button for your
platform. I'm going through this process on an M2 Macbook, so I downloaded the
Mac - Apple Chip version.

Open the installer and follow the installation process until the application
finishes the installation process.

#+caption: Docker Desktop on macOS
[[https://img.cleberg.net/blog/20240408-docker-local-web-server/docker-desktop.png]]

** Creating an Nginx Container

I prefer to use the command line to create containers, so the following commands
will be input via the terminal.

The following command will create a container, using the =nginx= image:

1. =-d=: Run this container as a daemon (detach)
2. =-p=: Allocate a port in the format =<external>:<internal>=
3. =-i=: Keep STDIN open even if not attached
4. =-t=: Allocate a pseudo-TTY
5. =-p=: Allocate a port in the format =<external>:<internal>=
6. =--rm=: Remove the container once it's done running

#+begin_src sh
docker run -it --rm -d -p 8000:80 --name web nginx
#+end_src

You can navigate to [[http://localhost:8000]] to see the resulting page.

#+caption: Default Nginx Container
[[https://img.cleberg.net/blog/20240408-docker-local-web-server/default-container.png]]

** Customizing the Nginx Container

Now that I have a container running the Nginx web server, I need to link some
volumes so that I can modify the site configuration and provide the web files to
serve.

Let's start with the new command, which adds two volumes:

1. =<your_content>:/usr/share/nginx/html=: This is the directory where you will
   provide the web pages for the server to serve.
2. =<your_config>:/etc/nginx/conf.d/default.conf=: This is the Nginx
   configuration file for your site.

To see the updates, you can delete the previous container in the GUI or run
=docker stop web= to stop the container. Once stopped, you can run the new
=docker run= command below.

#+begin_src sh
docker run -it -d -p 8000:80 --name web -v ~/Source/cleberg.net/.build:/usr/share/nginx/html -v ~/Source/cleberg.net/nginx-config.conf:/etc/nginx/conf.d/default.conf nginx
#+end_src

Here's an example of my development configuration file.

#+begin_src conf
# nginx-config.conf
server {
       server_name cleberg.net www.cleberg.net;

       root /usr/share/nginx/html;
       index index.html;
       autoindex on;

       access_log  /var/log/nginx/cleberg.net.access.log;
       error_log  /var/log/nginx/cleberg.net.error.log;

       location / {
                try_files $uri $uri/ =404;
       }

       listen [::]:80;
       listen 80;
}
#+end_src

[[https://img.cleberg.net/blog/20240408-docker-local-web-server/custom-container.png]]

* Customizing Deployment Actions

I am currently blogging with [[https://emacs.love/weblorg/][weblorg]], which uses a custom =publish.el= file to
build the static site. Within this file, I have configured my deployment process
to check for the =ENV= variable in thesh and if it's set to =prod=, the script
will set the base URLs to =https://cleberg.net=. If not, it sets the base URLs
to =localhost:8000= (which matches the port used in the container above).

Therefore, I have modified my =build.sh= script to build with =localhost= URLs
if =ENV= is not set to =prod=. It also prevents the build process from sending
the built files to the production web server.

#+begin_src sh
#!/bin/bash

if [ "$ENV" == "prod" ]; then
    echo "Environment = Production"              && \
    rm -rf .build/*                              && \
    emacs --script publish.el                    && \
    scp -r .build/* ubuntu:/var/www/cleberg.net/
else
    echo "Environment = Development"             && \
    rm -rf .build/*                              && \
    emacs --script publish.el
fi
#+end_src

You can modify the container in numerous ways and this approach allows you to
create complex scenarios for your web development purposes. I highly recommend
switching over to a container-based approach for simple, local web development.