Skip to main content

Running a Web Server Built with Rust in Debian

Running a Rust web server as a service behind a proxy is the sane way to go.

Part 1: Using Rust to build a bare-bone web server.  Let's assume this part is done because programming is easy. Part 2: Configuring the web server to run in the background as a service. Last part: Further configuring the web server to run behind a proxy so that to keep it safe from the Internet, and to utilize many features which have already been built with the proxy.

Running a service is operating-system dependent. Different operating system has a different configuration for running a service. In fact, some operating systems has a couple of ways to run a service. Yet, some may prefer to run a web server in a container like Docker. However, a container requires much more resources than a service.

There is no point in building a full-blown web server using Rust especially for a narrow business purpose, even though it can. Just like any web server, a Rust web server can always run behind a proxy. A full-blown web server has many general concerns which have already been  handled by matured services such as logging, caching, load balancing, firewall and security. Let the Rust web server focus only on the business concerns.

Notes: This documentation also applies to web servers built using C/C++/Java or other programming languages. Rust is in focus here because mentioning a specific programming language gives a reason to why it is done this way. In fact, when building with Rust, this should be the way to go. And for the proxy, there is a number of full-blown web servers that can run as proxies like Apache and Nginx. 

Web Server

A web server can be started from a command-line-interface (cli) terminal. Normally when building with Rust, a web server will take the IP and PORT parameters from the environment variables. The variables have to be exported to the process environment first before running the process which will consume the variables. A web server is a process. Use a .env file:
export IP="127.0.0.1"
export PORT="7000"
And execute the following command to export the variables:
$ source .env
In Debian, the 'source' can be replaced with '.':
$ . .env
And then run the web server:
$ ./server
Open a browser and point to http://localhost:7000. The main page from the web server will be loaded into the browser.

However, there is an issue. If the terminal is terminated then the web server will stop running. A web server must keep on running even when there is no one logging in the computer. Hence, a web server must run in the background as a service.

Web Server as Service

Copy the web server files into a system folder such as /opt/ so that other system users can also access it.

Create a service file web-server.service in /etc/systemd/system/:
[Unit]
Description="Web Server"
After=network.target

[Service]
Type=simple
Restart=always
RestartSec=5s
WorkingDirectory=/opt/web-server
ExecStart=/opt/web-server/server
Environment=IP="0.0.0.0"
Environment=PORT="7000"

[Install]
WantedBy=multi-user.target
Notice how the environment variables are set in the service file. The IP is set to "0.0.0.0" so that the web server can accept requests from anywhere.

The WorkingDirectory is where the web server files are. The ExecStart is pointing to the web server executable.

Whenever the web server panics and exits, the service will be restarted in 5 seconds and a new web server instance will be initiated. It will always restart after a crash because the configuration says so. A Rust panic is similar to an unhandled exception where an application will abruptly exit.

Make sure systemd find the new service unit:
$ sudo systemctl daemon-reload
Enable and start the service:
$ sudo systemctl enable web-server --now
Check the service status:
$ sudo systemctl status web-server
View logs:
$ sudo journalctl -u web-server
The service can be stopped indefinitely. It will not auto-restart:
$ sudo systemctl stop web-server
Again, open a browser and point to http://localhost:7000, or http://the-web-server-ip-address:7000.

The web server is serving on port 7000. For security reason this port should be kept behind a firewall. It should not be opened to the Internet, or to anywhere that poses a security thread.

The web server should be serving behind a proxy.

Web Server Proxy

Apache is a matured web server with a capability to be run as a proxy. It can also handle TLS so that the communication between the Rust web server behind the proxy and the browser is encrypted and to be accessed with https://. The Rust web server itself does not have to handle TLS. Read more on what else Apache can do so that the Rust web server behind the proxy does not have to.

Enable Apache modules:
$ sudo a2enmod proxy proxy_http rewrite
$ sudo systemctl restart apache2
Assuming the Rust web server domain is web-server.com.

Create a configuration file /etc/apache2/sites-available/web-server.conf for site web-server.com:
<VirtualHost web-server.com:80 www.web-server.com:80>
  
    ServerName web-server.com
    ServerAlias www.web-server.com
    ServerAdmin admin@web-server.com

    ProxyPass "/" "http://127.0.0.1:7000/"
    ProxyPassReverse "/" "http://127.0.0.1:7000/"

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>
Enable the site:
$ sudo a2ensite web-server.com.conf
$ sudo systemctl restart apache2
Open a browser and point to http://web-server.com. It will open the web server main page.

If there is a problem with the virtual host configuration run the following command to check the syntax:
$ sudo apachectl -t
Or, run the following command to list the virtual hosts:
$ sudo apachectl -t -D DUMP_VHOSTS

Secure Web Server

Let's Encrypt is a Certificate Authority that provides free TLS certificates. It can be applied to the web server through Apache.

Certbot is a free, open-source tool by the Electronic Frontier Foundation (EFF) that automates the process of getting and renewing Let's Encrypt SSL/TLS certificates to turn on HTTPS on web servers.

Install certbot:
$ sudo apt install certbot
$ sudo apt install python3-certbot-apache
Checking certbot scheduled task:
$ sudo systemctl list-timers
Get the TLS certificates for the web server:
$ sudo certbot --apache -d web-server.com
Now open a browser and point to https://web-server.com

Final Thought

The steps seems to be simple. However, every part requires deeper knowledge and experience on its specific subject. Those steps are stable for now but they may change in the future because software evolves. 

Rust is evolving in a very rapid pace. Maybe in the near future some or all of those steps will be absorbed by the Rust ecosystem. However, separation of concerns as shown in this documentation is the sane thing to do.

Comments

Popular posts from this blog

Setting Up PyScripter for Quantum GIS

PyScripter is a general purpose Python Integrated Development Environment (IDE). Quantum GIS (QGIS) is a desktop GIS application that can be extended with Python plugins. Both are open source softwares. We intend to use PyScripter as an IDE to build QGIS Python plugin. We are using PyScripter 2.4.1.0 and QGIS 1.6.0 in Windows. PyScripter does not come with Python. On the other hand, QGIS is built in with Python. Thus, we will setup up PyScripter to use the build in Python in QGIS. We assume both PyScripter and QGIS are already installed. Preparing PyScripter batch file We assume that QGIS is installed in C:\OSGeo4W\ folder and PyScripter is installed in C:\Program Files\PyScripter\ . 1. Copy qgis.bat in C:\OSGeo4W\ bin to pyscripter.bat 2. Edit pyscripter.bat to remove the last line that read something like this start "Quantum GIS" /B "%OSGEO4W_ROOT%"\apps\qgis\bin\qgis.exe %* and replace it with this in one line Start "PyScripter" /B "C:\Progr...

Everything has a Signature

Every data has a signature  which can be derived mathematically. All data of any size can be digested into fixed-size signatures. The signatures can be used to identify the data. Unique data has unique signature. Cryptographic hashing is a mathematical technique to hash or digest a data to reveal its signature. Digesting the same data always produce the same signature. Any minor change on the data will produce significantly different signature. A changed data is a different data. Data signature, hashing or digesting makes it possible for the data to be represented by its signature into a subsequent signing by combining it with one or more data signatures to produce a new signature representing a larger data set. Eventually, all data can be digested in chunks to produce a single signature. A signature can be verified by hashing the same data again which will produce the same signature. This introduces data signing-verification concept. In a communication between two parties, ...

Access Control

Access control is about controlling user flow within your application. Do not mistaken access control with security which is a bigger subject in itself. Access control begins by authenticating user and limit his or her activity in your application. An activity is something like creating, updating or deleting a content. There are always finite number of activities that can be done in a given application. Each user can be assigned to a set of activities that he or she is allowed to do. Access control is usually tied to session management. However, you do not need session management to have access control. When a user log in, a session is created so that the user is remembered for the subsequent access. Otherwise the user has to keep on providing his or her credential for each access. We can also keep a list of activities that the user is allowed to do in the session record. Some applications let the session alive indefinitely and some applications time out user after a duration of inacti...