Apache 2 serving both dynamic and static files as a web server is a pretty typical and tried setup. It is basic and easy enough to implement. However, a need to server static files separely often arises.
For example, this may be useful because we may want to store static files on a separate domain in order to increase the performance of the site. That is, by having a different webserver that is dedicated strictly to static files, we can optimize that server in a way that would be impossible if it also needed to serve dynamic pages alongside the static files. This may also prevent unneeded overhead of cookies being sent with HTTP requests for static files, thereby reducing network traffic.
The documentation for Django web-framework specifically suggests two separate webservers for serving dynamic and static pages.
A typical way to do that is to serve dynamic pages using Apache and static files using Nginx. Particularly, one can employ the setup called Reverse Proxy in which the Nginx receives all requests for all resources and then decides what to do with each request.
If a request is for a static file, then the Nginx server will promptly deal with that task. If, however, the request is for a dynamic resource, the Nginx will pass the request to the Apache server which will in turn serve back the needed resource.
This may look as follows
ubuntu@ip-xxx-xx-xx-xx:~$ sudo netstat -tlpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 13390/nginx: master
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN 7136/apache2
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 641/systemd-resolve
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1038/sshd
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN 6123/postgres
tcp6 0 0 :::22 :::* LISTEN 1038/sshd
That is, all icoming TCP requests on default port 80 are received by the Nginx server listening on that port. If a request is for a static file, it serves it. Otherwise, it passes the request to the Apache, which is listening on port 8080 locally. This is the Reverse Proxy setup. In this setup the Nginx is the proxy server, which makes it look to the outside world as if it is doing all the work.
Here is a possible (actual, working) configuration for the Nginx server in such a setup
server {
listen *:80;
server_name www.name.org name.org;
access_log /var/log/nginx/name-access.log;
location / {
proxy_pass http://localhost:8080;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~ /\.ht {
deny all;
}
location /static/ {
root /var/www/path/to/project;
}
location /media/ {
root /var/www/path/to/project;
}
#location ~* ^.+\.(jpg|js|jpeg|png)$ {
#root /some/where/on/your/disks;
#}
# put your static hosting config here.
}
Similarly, the Apache configuration may look like this
<VirtualHost 127.0.0.1:8080>
ServerName www.name.org
ServerAlias name.org
WSGIDaemonProcess name display-name=%{GROUP} python-path=/var/www/path/to/project
#WSGIApplicationGroup %{GLOBAL}
WSGIProcessGroup name
<Directory var/path/to/project>
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error-name.log
CustomLog ${APACHE_LOG_DIR}/access-name.log combined
LogLevel info