Introduction or what the article is about
In this article I will tell and show how you can host a site on servers from timeweb (hosting provider). This provider offers a wide range of development platforms/CMS that are used to create a site. But in this article I will only tell you how to deploy a site written in Django, because I understand this.
In addition to what was said earlier, I also want to show how you can set up your project/site so that if you need to implement new features, or fix them), it is no more difficult than pressing one button. We will do this through bash, git and ssh.
In addition to providing regular (virtual) hosting, timeweb provides such a service as VPS. So, on timeweb, your site can be hosted in two ways:
- Quick and easy, although not without nuances. The point is to use the provided functionality without having to use the terminal. As you will see later, you will still have to use it.
- A bit tedious and confusing, but with much more freedom in placement. The essence of the second method is to create your VPS and configure the server manually. (Phusion Passenger/Gunicorn) (Nginx/Apache2)
This article is divided into 3 main parts:
- The first is Preparation. It needs to be done regardless of which deployment platform you have chosen.
- The second is Deployment on a virtual hosting. It will tell you how to deploy a site to a virtual hosting, with minimal interaction with the terminal.
- The third is Deployment on a VPS. It will tell you how to create and configure your VPS on timeweb. After which the Django application itself will be deployed.
I will demonstrate both methods. I will explain the features and nuances of both, and why VPS is better, in my opinion. You can go straight to the comparison here.
Features of this tutorial
For demonstration I will use a specially made for this django application. This application was specially made with all the features that your Django site will probably use:
- Working and setting up with the database
- Working and setting up mail
- Working with statics
- Working with media files
- Working with translations
- Testing the application
I am constantly working on this application, because I am going to test it on other hostings (not only timeweb). In the end, I see it as one big interactive test of hostings, on how friendly they are to Django sites.
Preparation, or how to buy a domain
To buy a domain, go to https://hosting.timeweb.ru/domains/registration. There will be a field for entering the desired domain, enter it, register:

Selecting and registering a domain on timeweb.com
Afterwards you will be redirected to the domain settings page, there you don't have to take an SSL certificate. A little later, we will install a free one from LetsEncrypt

Setting up a new domain on timeweb.com
Now that we have a domain in hand, let's link it to the site and install an SSL certificate. All this can be done on this page: https://hosting.timeweb.ru/domains/settings?fqdn=DOMAIN_NAME
Where DOMAIN_NAME is a full name of the newly acquired domain.

- You will need to attach the domain to the created site. After that, you will have to wait from 15 minutes to 24 hours until the DNS is updated.
- After clicking, a selection of available SSL certificates will be presented. Choose LetsEncrypt and move on
Deployment on virtual hosting
Creating a database
We already have a website and a website linked to it. Let's add a database to the list of completed tasks. Creating and editing databases is done here -> https://hosting.timeweb.ru/mysql

Database creation page
You will need to fill in and then remember the following values:
- Database name (cs86772_bd for me, respectively)
- Username (will match the database name)
- Database password
Also, if you are going to host the site on a VPS, do not forget to add an additional access address to the database.
Creating mail
Setting up mail is even easier than setting up a database. On the page https://hosting.timeweb.ru/mailman, click on "Add mailbox" and enter the required data. You will need to remember the following data (they will be needed for setting up later):

- some@cs86772.tw1.ru - a login to enter (EMAIL_HOST_USER)
- 743Ew0x35 - a password to enter (EMAIL_HOST_PASSWORD)

- smtp.timeweb.ru - post server to send the mail (EMAIL_HOST)
- 465 - a post to connect to post server (EMAIL_PORT)
Connect to a virtual hosting via SSH
Having finished with the preparatory part, we can proceed directly to the deployment. To be able to work with a remote server, we need to connect to it. There are several ways to do this, the easiest is to use the built-in commands and utilities of the hosting itself.
And to get access via SSH, you can use the browser terminal from timeweb.
Login to the web terminal
Start page styled with command
Installing a virtual environment
Unfortunately, we can't use the built-in venv module to create a virtual environment. Instead, we'll have to work like this. Download the archive with the required python version:
At the time of writing this article, virtual hosting from timeweb supports only two versions of python:
- Python 3.10 - on Ubuntu 22.04
- Python 3.6 and Python 2.7 - on Ubuntu 18.04
Finally, let's create a virtual environment, like this:
Now you can activate it and install the necessary packages for our site to work.
Transferring website files
The site itself is required for the site to work. It must be somehow transferred to the hosting. Therefore, to transfer site files, you can use the built-in file manager or the terminal command - scp.
And if your project uses a source code version control system, i.e. git. Like me, then you can simply clone the required repository:
- Where bddt3.site/public_html is the site directory
- Where source is the directory into which the Django site will be cloned
After successfully transferring the site files, we finally activate the virtual environment and install the necessary packages:
Configuration of static and media files
What do I mean by configuring static and media files? The thing is that when collecting static files or uploading files to the server. They, the files, will be placed in the static and media directories respectively. And these directories, in turn, will be created relative to the root directory of the project. That is, where the manage.py file is located.
The joke is that the web server does not have access to the root directory of the project, but it does have access to the public_html directory. We need to create static and media directories in public_html, and then create soft links to them from the root directory of the project. This can be done like this:
The main thing is to be in the directory next to the manage.py file. That's where the soft links should be created.
Working with hosting configuration files (.htaccess and wsgi.py)
Setting up .htaccess and wsgi.py files has its own specifics, which are specific only to timeweb hosting. Both .htaccess and wsgi.py files must be in public_html.
We have the following project structure:
- ~/bddt3.site <- You are here
- venv
- public_html
- cgi-bin
- media
- static
- source
- Website
- Website
- settings.py
- Frontend
- Backend
- manage.py
- settings.json (This file will be discussed in the next chapter)
- media -> ../../media
- static -> ../../static
- requirements.txt
- .htaccess (In this chapter we work with these files)
- wsgi.py (In this chapter we work with these files)
- index.htm
The purpose of the .htaccess configuration file is to redirect requests directed to the Apache web server to our Django application. You also need to know one important feature of timeweb hosting. They use a special hosting module for hosting -> mod_wsgi.
Your .htaccess file must contain the following for this to work:
You also need to write a simple wsgi (the file should be called wsgi.py) script for work and place it in the same directory next to .htaccess. Here are the contents of the wsgi.py file:
Everything that is highlighted is what you need to change for your site.
- Path to the virtual environment activation script
- Path to the root directory of the project (this is where the manage.py file is located)
- Path to the settings module (relative to the path specified in the second selection)
Setting up our Django site
When you've finished creating and configuring files for the Phusion Passenger gateway and Apache2 web server, you can edit the Django site configuration file, settings.py.
If you're following my example, you might have noticed that my Django site configuration file is slightly modified. It takes all the configuration data from another file - settings.json.
An example of what my modified file looks like - settings.py
The configuration file is located in the root directory of the project, next to manage.py. Its contents will look something like this:
This is already a fully configured file using all the data I told you to remember.
- To find out what and where to insert for the database, see the chapter on creating a database - Creating a database
- To find out what and where to insert for mail, see the chapter on creating and mail - Creating mail
I changed DEBUG to false because we are deploying a Django project on a production server. You also need to add the name of the domain you purchased to ALLOWED_HOSTS. Plus, don't forget to change SECRET_KEY to a new one.
Finish up the deployment
And the final touches to complete the site deployment are the following commands:
- Database migration [./manage.py migrate]
- Collecting static files [./manage.py collectstatic]
- Compilation of translations (if any) [./manage.py compilemessages]
- Checking tests (if any) [./manage.py test]
After successfully completing each of them, you can consider that the site has been successfully deployed.
Deploy to VPS
So, if you read the first part, you couldn't help but notice the significant disadvantages that virtual hosting brings. For example, you won't be able to implement asynchronous communication between the web server and your application (ASGI). Or you won't be able to create a multilingual site.
On VPS, such difficulties are not expected. And I will show you how to host a site on VPS.
Create VPS
VPS and virtual hosting are two different entities and work with them differently. So, to create and manage your virtual machines you will need to go here - https://timeweb.cloud.

After this page, you will be given the opportunity to configure your server. I will make the most dushmansky server that I can, as always. As a result, the simplest server will cost you 6.37$:

- I choose Ubuntu 22.04
- Physical location of the server (This is not so important if you use CDN or have a monolingual audience)
- What hardware to use (The more complex the project, the cooler you need to take)
- Will I have a public IP. That is, will I be able to enter its address in the search and get something
- SSH key, for those who are obsessed with security and those who are too lazy to enter a password to log in. (You need to send the public part of the key)
Editing DNS
This is done quite quickly. Since we have already purchased a domain, we will only need two records A and AAAA. More specifically, we will need to change the default IP to the IP of our VPS server. On this page, select the VPS that you recently created and copy its IPv4 and IPv6.

After that we change the DNS records for our domain, in my case it is bddt3.space:

Thus, when accessing the specified domain (in my case it is bddt3.space), the DNS server will point to the VPS server we need (that is, the one we created).
Create a database on VPS
Any site, one way or another, requires a place to store data. This hosting provider supports many databases (MySQL, PostgreSQL, MongoDB ...). I will demonstrate working with MySQL because I am well acquainted with it.

So you will create a database and pre-configure it. After its successful deployment (and this takes 5-10 minutes), you will need to edit the settings.json file, but more on that below, but for now I will show you what data we will need to know:

- Public IP - 89.169.1.110
- User login - gen_user (Default value)
- User password - *******
- Database name - default_db (Default value)
- Connection port - 3306 (Default value)
This data will be needed in the chapter on connecting to the MySQL database. For now, let's connect to the VPS and transfer the site.
Connect to the created VPS via SSH
We have successfully created our first virtual server (and database) on Timeweb, now we need to connect to it. For this we will use SSH. And in order to be able to connect to our server we need to know its IP and password to it. All this comes to the mail that you specified when registering an account on Timeweb.
Or, alternatively, you can look in the hosting admin panel. Copy the specified command and use it in the terminal:

The password can be reset if necessary, and the username to which you can always connect is root - always. Let's connect to our server:
Since I am still working and sitting on Windows, I will use the simplest and most accessible method, from here on - PowerShell.
Connect to the server by the key (optional)
I predict that you will have to log into the remote server very often, if only because the connection can be constantly interrupted, and manually entering the password to connect is quite a task.
Therefore, I suggest creating a key pair for authorization without a password. To do this, on your work computer, enter the command:
- Where the -t flag is responsible for the type of the generated key
- Where the -f flag is responsible for the path to the file (which may not exist) where the key will be saved
After generation, you will have two files, bddt3 and bddt3.pub. The first (bddt3) is a private key, keep it like the apple of your eye, it is needed for authorization. The second key (bddt3.pub) is distributed to all remote servers that you want to access without entering a password.
It remains to execute one more command, namely, to transfer the key to the remote server that you want to access using the key.
- Where .ssh/bddt3.pub is the path to the public part of the key
- Where USERNAME is the username through which you want to get to the server, usually root if no other users have been created yet.
- Where SERVER is the address of the remote server. This can be either IPv4 or a domain name.
We are done. After that, to enter the server, use this command:
Installing the necessary packages
Now it's time for Ctrl-C, Ctrl-V. There will be a few commands that will install the necessary packages on your server:
And in order to install the latest versions of Python, you will need to update the Ubuntu package manager repository index.
And then you can install Python and everything you need:
Now let's talk about why I installed all of this, and what each of these commands did:
- apt-get update - Always run it first when installing any package. It syncs the application package index and updates all dependencies if necessary.
- apt-get upgrade - Installs the latest versions of installed packages on the system.
- apt-get install gettext libgettextpo-dev - it installs the dependencies needed to generate translations for your sites (which use the gettext utility)
- apt-get install pkg-config default-libmysqlclient-dev build-essential - necessary dependencies for working with MySQL databases.
- apt-get install nginx - to start the web server
- apt-get install gunicorn - to redirect requests from the nginx server to our django application
- apt-get install python3.12 python3-dev python3.12-venv - to be able to create a virtual environment when running python applications
My "unnecessary" package is selenium. I need it for my functional tests to work. And for it to work, it will need the Firefox browser, which we will install as a .deb package. Oh boy, this is quite an adventure \(°〇°)ノ. I invite everyone interested to visit the official Mozilla website and run one command after another.
In addition to firefox, you will also need to install geckodriver. The latest releases can be found here: https://github.com/mozilla/geckodriver/releases . And now, the command to install this geckodriver:
After downloading (wget) and unzipping geckodriver (tar -xzvf), we then placed it in the /usr/local/bin/ directory so that all applications had access to the driver.
Create a new user
This step is mandatory and do not think about making a site with root rights. Now you will need to create a user with root privileges and a home directory.
The first command will create a user named "site", create a home directory for it (flag -m) and set the default shell, i.e. bash. The second command will set a password for the new user. The third will add the user "site" to the sudo group, which is able to execute all commands, only using the sudo command.
Transferring the project to the server
The base for our server is ready, now let's work on the site files themselves. I'm going to create a simple file structure where I'll get my project files using git and copy them to the source directory. I'll also create a virtual environment:
After running all these commands, you should have the following project structure:
- bddt3.space <- You are here
- venv
- source
Now, activate the virtual environment and install the necessary packages from source/requirements.txt:
There shouldn't be any problems here, but if they do, read the error logs carefully. Often, these are simply uninstalled dependencies on the server, which can be easily fixed using the apt package manager.
Let's try to run the installed Django application (from the directory with the manage.py file):
Setting up mysql database
You will get an error that the settings.json file was not found. This is a configuration file that I use as a proxy instead of writing directly to settings.py. I did this so that I could safely add the settings.py file to the git repository and to simplify deployment.
Here is an example of such a file (settings.json), create it in the source/Website directory:
Как ты видишь, я уже использую MySQL в качестве базы данных. Что нужно знать для подключения к базе данных из VPS:
- First, you need to know which backend to connect to - django.db.backends.mysql
- Second, the database name- default_db
- Third, the username - gen_user
- Forth, the database password - aD9bN5oV3pjD7qJ9
- Fifth, the database host name (address) - 89.169.1.110
- Sixth, the connection port - 3306
All this data can be obtained when creating your database, the process of which I described in the corresponding chapter at the beginning.
How do I transfer data from settings.json to Website/settings.py? In the settings.py file, I open the settings.json file and read the data from there, like this:
I use the JSON format because it is simply very convenient to work with it via Python.
Finishing up the project transfer
By the way, we can already run tests and see what works and what doesn't. Everything should work. So, we have successfully uploaded our site to the server and even passed all the tests. This means that it is time to configure nginx, after which we will connect our site to the nginx web server via gunicorn.
Super fast Nginx configuration (very optional)
Next I'm going to go into detail about what each file is used for, how to start and restart nginx, plus how to add sites to nginx. If you're interested, you're welcome, but if not, you can use the server-setup.sh script I left in the repository.
To use it, enter:
- Where YOUR_DESIRED_DOMAIN is the desired domain
- Where on_https is a flag that tells to configure redirect to HTTPS protocol
This script will create the corresponding configuration files and will be reloaded.
Configuring Nginx
Along with the project files, you will also receive default configuration files for configuring nginx - nginx-server-http_only.conf, nginx-server-https_301.conf, nginx-server-https.conf. For now, open the file nginx-server-http_only.conf, you will see the following configuration for our site:
- In this configuration, we set up the port on which we will listen for incoming requests.
- The name for our server (domain name). In my case, it should be bddt3.space.
- The folders that this server will serve. At a minimum, you need to set up the root directory "/". But this is not all, my site uses various statics in the form of pictures and icons. Plus media files that are uploaded directly by the user.
So the final version of this configuration will look like this:
To make sure we don't forget, let's immediately create the media and static directories in the ~/bddt3.space directory and soft links to them. Soft links to them are created to give the server access to them.
All the necessary directories have been created and now we are ready to create soft links to these directories:
Now, any file that is created in the ~/bddt3.space/source/Website/static or ~/bddt3.space/source/Website/media directory will be available in the ~/bddt3.space/static and ~/bddt3.space/media directories.
To check this, you can run the collectstatic command and make sure that all files, although copied to ~/bddt3.space/source/Website/static, are also available in ~/bddt3.space/static.
403 Forbiden error - how to solve (optional, I hope)
Another very common problem is that the server can return a 403 response to a request for some static file. This is often due to the fact that the user www-data does not have permission to read certain files. The nginx configuration file specifies the user on whose behalf the web server is launched.
There are three ways to fix this:
- Replace the user in the /etc/nginx/nginx.conf file
- Give everyone access to read files
- Add the user www-data to the group of the user who launches the application.
I will describe the 3rd because this is, in my opinion, the simplest and most correct way. And you just need to run one command:
- site - the name of the group to which you want to add the user (it will match the user name)
- www-data - the name of the user you want to join the group.
Now, all statics and all media files on the site should be available.
Finish up a Nginx set up
Let's finish setting up the web server and copy the created configuration file to /etc/nginx/sites-available:
Now let's do the same as with the static and media directories, create a soft link to this configuration file. But first, go to the directory where this link should be:
Let's restart the nginx service using systemctl so that the changes take effect:
I think it's worth trying to visit our website now - bddt3.space.

And yes, you should see something like this. Why is this happening, what is this "Bad Gateway"? It's all because one line, in the site configuration file /etc/nginx/sites-available/staging-nginx-server.conf.
In fact, the nginx server forwarded my GET request to the specified socket, but nothing is connected to it yet. This is where gunicorn comes into play.
Seting up a Gunicorn
The almost ready configuration file is located in the same place as the nginx server configuration file - ~/bddt3.space/source/gunicorn.service. This is a file describing the work of the linux daemon, here are its contents:
This service (daemon), launched by the user site and with its privileges, will be rebooted every time an error occurs (Restart=on-failure). This daemon will work in the directory specified in WorkingDirectory. And it will do what is specified in ExecStart, that is, launch the gunicorn server.
When launching gunicorn, we also specified which socket to connect to and where to redirect requests - to our Django application.
Create the same file in /etc/systemd/system/ and edit it by inserting your user, your domain and your socket. Now let's launch the service and make it start on the server after boot.
Now everything will work. We have created a special service that starts the gunicorn server at startup, and it starts our django application. After refreshing the tab, you should see the following:

This completes the process of deploying a Djanog site on a VPS from reg.ru. I also recommend reading the next chapter on how to put this site on the new HTTPS protocol.
Migrate to HTTPS (optional, although not really)
In order to place our site on the HTTPS protocol, we will need to get a special certificate. We will get it from LetsEncrypt. It is free, but what is even cooler is that everything can be done through the command line, which means automation. Look, in order to configure the nginx web server for https, you will need a certificate and a key to it.
The LetsEncrypt team made a special utility, which is very cool in terms of supported technology stacks for certification. Here, for example, is a page for generating, signing and issuing certificates for sites on nginx and using pip. It is just dope ;) And you do not need this headache with self-signed certificates that no one trusts, and as a result, no one visits the site.
Activate the virtual environment and install the program:
Now we generate and sign up the certificates:
This command will generate and sign up certificates, which will be placed in /etc/letsencrypt/live/bddt3.space. You will see an interactive prompt like this:

- Asks to enter email
- Agree to sell your soul and the soul of your site)
- Registration, optional
- Selecting domains (subdomains) for which this certificate will be valid. If you simply press ENTER, the certificate will be applied to all.
- Path to the certificate (for configuring nginx)
- Path to the key (for configuring nginx)
You can also set a cron task to update the certificate every month:
All that remains is to change the configuration in sites-available, this is done like this:
The difference from the previous configuration is that we changed the port and added ssl_certificate and ssl_certificate_key and the paths for which certbot will tell you. That's all, on how to add https to your site.
But you may have noticed that when trying to get your site via regular http, it will no longer work. You will need to make a separate configuration for port 80 and make a 301 redirect to the https version. This is considered good practice. To do this, create another configuration file in /etc/nginx/sites-available, for example http_301_redirect-staging.bddt.space, with the following:
Where HOST_PLACE_SETUP is your site's domain, for example bddt3.space. This configuration makes a 301 redirect from any http pages to https pages.
Comparison of launching a website on a Hosting and on a VPS
| Testing capabilities | No limit | No limit |
| Custom project structure | Limited | No limit |
| Automation of deploy, setting up etc. | Limited | No limit |
| WSGI server | Supported | No limit |
| ASGI server | Not supported | No limit |
| Web server | Apache2 | No limit |
| Migration to HTTPS | Seamless | Hard |
| Database setup | Easy | Easy |
| Domain linking | Seamless | Easy |
| Price | Cheap | Less cheap |
| Translations | Not supported | Supported |
| Metrics | TimeWeb Hosting | TimeWeb VPS |
|---|
Honestly, I would rather deploy sites on a virtual hosting than do it myself on a VPS. But the limitations in the versions of Python used, the inability to use other databases, and the cherry on the cake, the inability to support ASGI and built-in django functionality for localization, really put me off.
Conclusion
And here is another hosting provider conquered and studied. Now you know how to host sites on Timeweb. From my experience, I will say that hosting a site on Timeweb is more difficult than on the same beget. There are too many pitfalls and non-obviousness. I hope I have analyzed them all and shown acceptable ways to solve and bypass them.
I also hope that this article helped you figure out how and where to deploy your site written in Django and I also hope for your kind comment and that you might want to share this article with a friend. In any case, see you in the next article (⌒‿⌒)