A set of scripts to help you host your side projects on VPS using Linux and Docker.
Explore the docs »
View Demo
·
Report Bug
·
Request Feature
Table of Contents
Denlin: Docker Engine On Linux CLI Tool Screenshot
The Problem: I have one VPS with a single IP address. I want to be able to experiment with different programming languages and host my various side projects on my single VPS.
The technology stack:
- Ubuntu Linux Operating System
- Docker Containers
- Github Version Control
- Github Actions CI/CD Pipeline
- Nginx Reverse Proxy Server
- Let's Encrypt SSL Certificate
- Performance Monitoring Tools
- Reverse Proxy
- Dockerfile Templates
- Docker Compose Templates
Self hosting done right can reduce the cost of hosting, but introduces additionaly complexity which will cost you taking longer to launch.
The "Denlin Docker Engine on Linux CLI Tool" is a set of scripts to help DevOps beginners get their VPS set up quickly with Linux and Docker, using these scripts.
The Set Up: In my directory root, I have these apps:
- /svelte-counter
- /python-django-achievementhq
I want to be able to run all my apps at the same time on my VPS.
My VPS hosting is provided by Hostinger, but you may choose any VPS host.
Tested on Ubuntu 22.04
Docker hosts applications inside of docker containers
Version control provided by GitHub.
Github Actions for Continuous Integration/Continuous Delivery pipelines
Nginx as the HTTP web server, reverse proxy and content cache.
Let's Encrypt Nginx Companion provides SSL Certificates.
htop provides interactive process viewing and system monitoring.
I have chosen Hostinger
In your hosting provider's control panel, you'll want to chose an operating system for your VPS.
- Choose a location closest to your customers
- Choose Plain OS, not an OS with a control panel
- Choose Ubuntu for your operating system
- Choose a VPS hostname(optional)
- Set a secure root password of at least 12 characters
- We can skip creating an SSH Key as we will create that later(if provided)
- In your hosting services control panel, find your IP address for your VPS
- On your local machine go to your terminal client.
Tip
Git Bash is an application which provides an emulation layer for a Git command line experience. Windows users should use the Git Bash terminal client. Mac users can use their native command line shells, provided they have Git installed.
Log into your VPS
ssh root@your_ip_addressIf it's your first time logging in, you will get this message that you must accept by typing yes followed by the enter button, before being allowed to log in.
The authenticity of host 'your_ip_address' can`t be established.
RSA Key fingerprint is SHA265:a_hashed_value_here
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yesAfter key fingerprint has been added to your local environment, the terminal will ask you for your password.
Warning: Permanently added 'your_ip_address' (RSA) to the list of known hosts.
root@your_ip_address`s password: your_password_goes_hereYou should now be logged in.
Before installing Git, ensure your system is up-to-date:
sudo apt update && sudo apt upgrade
sudo apt-get install git
Once installed, verify the version of Git to ensure it’s installed correctly:
git --version
You should see an output like:
git version 2.x.xYou can now reboot the server to ensure all changes take effect.
sudo reboot
git clone https://github.com/monatemedia/docker-engine-on-linux.git
cd docker-engine-on-linux
bash install.sh
cd ~
denlin create-new-user
After the new user has been created, log out of the VPS and then log in with your new user account.
Whenever logging into your VPS from your local computer, you will always be asked for your username ssh your_name@your_ip_address and your password. This is fine but can be annoying if you have already secured your personal computer with a strong password.
We have the option to in future be able to log into the VPS with only our username using an SSH key-pair.
Important
RSA encryption is a public-key cryptographic system known for its reliable encryption and decryption method. Typically, RSA is used for encryption of shared keys exchanged over the internet to establish a secure connection. RSA encryption has different key sizes which range from 1024 to 4096 bits.
A SSH key pair in Linux is a combination of a public key and a private key that are used to authenticate a remote user to an SSH server.
- Public Key
- Used to encrypt data and can be shared with any SSH server
- Private Key
- Used to decrypt data and should be kept secret and encrypted
Run this commad and follow the prompts
denlin setup-ssh-login
To install Docker Engine, use the following command:
denlin docker-install
If you did not get the Hello from Docker! message, you can test your installation by running:
docker run hello-world
You can use a single, centralized nginx-proxy container to manage your applications. This container will act as a reverse proxy and route traffic based on the subdomain to the correct application.
Important
Our containers on Docker do not communicate via ports and IP addresses as in traditional networking, but instead use Docker's built-in networking feature, where containers are identified by container name and communicate over a network which Denlin calls proxy-network.
Containers can be identified by a tagged name using the -t flag, or the name assigned by Docker.
To create the Nginx proxy, use the following command:
denlin services
Then select the option setup-nginx-proxy.
Once the Nginx proxy has been set up, visit your IP address. You should get HTTP Error 503(Service Unavailable) status code message from Nginx.
Test your installation by creating a test container:
denlin services
Then select the option new-hello-world-container.
For this test, for the service name, you can use the name hello-world.
Tip
The Hello World image used in this script will displays a simple "Hello, World!" message in the browser
Once done, use search to find your DNS records in your web domain hosting provider's control panel.
Add a new DNS record using the output from the script, example if using a subdomain:
| Type | Name | Points to | TTL |
|---|---|---|---|
| A | hello-world.monatemedia.com | 77.243.85.71 | 14400 |
Also note that if the application will be hosted in the main domain, the Name value will be @.
Now visit your domain or subdomain in the browser, and you should see your Hello World website over HTTPS.
Now it's time to do some configuration on our local development computer. Make sure you are navigated to the folder where you store your projects on your local computer.
On your local computer, check if you have the GitHub CLI installed.
gh --versionYou should recieve an output like this:
gh version 2.65.0 (2025-01-06)
https://github.com/cli/cli/releases/tag/v2.65.0If the GitHub CLI isn't already installed on your local computer, you can install it by following the official instructions. You may also install it using the command line.
On Windows, you can it install with:
winget install --id GitHub.cli
Important
The Windows installer modifies your PATH. When using Windows Terminal, you will need to open a new window for the changes to take effect. (Simply opening a new tab will not be sufficient.)
On Mac, you can install with Homebrew:
brew install gh
Test the installation again.
gh --versionYou should recieve an output like this:
gh version 2.65.0 (2025-01-06)
https://github.com/cli/cli/releases/tag/v2.65.0If you you get an error, close the terminal window and try again with a new terminal window.
Create a new project on your local computer. Make sure you are navigated to the folder where you store your projects, right-click in the folder and open a GitBash terminal in this folder. From here the process will create the project folder for you.
Create a new React project with Vite.
npm create vite@latest
Complete the flow by selecting (y) to install packages, choose a Project name, framework and options like variant. Change into your directory, run npm install and npm run dev.
Need to install the following packages:
create-vite@6.1.1
Ok to proceed? (y) y
> npx
> create-vite
√ Project name: ... react-counter
√ Select a framework: » React
√ Select a variant: » TypeScript
Scaffolding project in C:\Users\Lenovo\Coding Projects\react-counter...
Done. Now run:
cd react-counter
npm install
npm run dev
Lenovo@DESKTOP MINGW64 ~/Coding Projects/
$ cd react-counter
Lenovo@DESKTOP MINGW64 ~/Coding Projects/react-counter
$ npm install
Lenovo@DESKTOP MINGW64 ~/Coding Projects/react-counter
$ code .
Lenovo@DESKTOP MINGW64 ~/Coding Projects/react-counter
$ npm run devYou should now be able to visit your new app at http://localhost:5173/
To create a Dockerfile, use create-dockerfile command in Denlin's Services Menu.
Important
A Dockerfile is a template for an image of our application. The image is then a template for a Docker container, which is a runnable instance of the Docker image, and uses a docker-compose.yaml file to run the image.
We will run multiple Docker containers to host our applications.
Call the Services Menu
denlin services
From services menu select create-dockerfile.
Important
To build and run containers in your local development environment, make sure that you have Docker Desktop running.
Run the following command in your project root (where your Dockerfile is located):
docker build -t react-counter .
This will:
- Use Node.js to install dependencies and build the app.
- Copy the dist/ folder to an NGINX container.
Run the following command to start your container:
docker run -d -p 8080:80 --name react-counter-container react-counter
This will:
- Run the container in detached mode (
-d). - Map port 8080 on your machine to port 80 inside the container.
- Name the container react-counter-container.
After running the container, open your browser and visit: http://localhost:8080
You may also access your container through Docker Desktop.
Caution
When debugging your container, you must be sure that the container runs on Docker Desktop without any issues before attempting further deployment.
If the application does not run on Docker Desktop, the application will not run in deployment.
To stop the running container:
docker stop react-counter-container
To remove it completely:
docker rm react-counter-container
Check running containers:
docker ps
Check logs of your container:
docker logs react-counter-container
To create a GitHub PAT, use create-github-pat command in Denlin's Services Menu.
Call the Services Menu
denlin services
From services menu select create-github-pat
The create-github-pat will automatically log your VPS and local computer into the GitHub Registry using the PAT.
Tip
To access the GitHub Container Registry we first need to create a PAT.
To create a new token visit: GitHub Create New Personal Access Token.
You can also get there in GitHub by clicking on your profile -> Settings -> Developer Settings -> Personal access tokens -> Tokens(classic) -> Generate new token
To generate a new personal access token (classic) for a server named VPS 1 with write:packages, delete:packages, read:org and admin:public_key scopes, enter the name in the Note input box, select the corresponding boxes, then select Generate token
Note: VPS 1
Select 90 days till expiry
Scope:
-
write:packages -
delete:packages -
admin:org-
write:org -
read:org -
manage_runners:org
-
-
admin:public_key
Copy and keep your token in a safe place. Do not share your token with anyone or commit it to version control systems like GitHub or the GitHub Container Registry.
To use the gh CLI, you need to authenticate the user on your local machine.
Open a GitBash terminal in your projects folder and log into GitHub CLI.
gh auth login
Follow the interactive prompts to log into your GitHub account, using your PAT when asked for your authentication token.
What account do you want to log into? GitHub.com
What is your preferred protocol for Git operations? SSH
------
Generate a new SSH key to add to your GitHub account? (Y/n) Y
--or--
? Upload your SSH public key to your GitHub account? [Use arrows to move, type to filter]
> C:\Users\Lenovo\.ssh\id_rsa.pub
Skip
(If the key already exists, use that one)
------
Enter a passphrase for your new SSH key (Optional)
Title for your SSH key: (GitHub CLI)
How would you like to authenticate GitHub CLI? Paste an authentication token
Paste your authentication token: `****` Tip
You will find the PAT saved in the .env file in the root of your project as the variable CR_PAT from using the create-github-pat function in the previous step.
If your GitHub authorization fails, please try again.
gh auth logout
gh auth login
GitHub CLI may ask you to authenticate your device with the browser, by giving you a one-time code and asking you to log into GitHub with https://github.com/login/device
Lenovo@DESKTOP-UQBI21I MINGW64 ~/OneDrive/Coding Projects/react-counter
$ gh auth login
! First copy your one-time code: E90B-9AAA
Open this URL to continue in your web browser: https://github.com/login/device
✓ Authentication complete.
✓ Logged in as monatemediaTo initialize your GitHub repository, use initialize-git-repository command in Denlin's Services Menu.
Call the Services Menu
denlin services
From services menu select initialize-git-repository.
Warning
These scripts assume that your project is on the main branch of your repository.
If your project is on master, please go into the settings of your repo and change the main branch from master to main.
We want to store our GitHub Personal Access Token (PAT) in the GitHub Actions Secrets so that GitHub is able to log into our GitHub Registry and save our image into the registry.
To store your PAT as a GitHub secret, use create-github-actions-secret-pat command in Denlin's Services Menu.
Call the Services Menu
denlin services
From services menu select create-github-actions-secret-pat.
This script stores your PAT in your project's Repository secrets.
To create and store your Docker image to the GitHub Container Registry, use store-docker-image command in Denlin's Services Menu.
Call the Services Menu
denlin services
From services menu select store-docker-image.
Important
Docker Desktop should be running on your local machine to store your Docker image to the GitHub registry. The process cannot succeed without it.
Now, we want to host our container on our server. For that we will use docker-compose.
docker-compose is basically a yml file where we specify the properties of our container, and that way we can just run the docker-compose file, and not have to use a docker run command, making it much easier to run containers.
To create and store your Docker image to the GitHub Registry, use create-docker-compose command in Denlin's Services Menu.
Call the Services Menu
denlin services
From services menu select create-docker-compose.
For more examples, please refer to the Documentation
Always running docker build and docker push to bring our new image to our server is annoying, so we will create a GitHub Action to automate this process.
The action will run every time you push changes to the main branch of your repository, and triggers the commands we want to run. We will run commands that will bring the image to the VPS server.
So every time we push our code changes ot the main branch of our repository, we also want to pull the changes into our server, and then restart the container.
We have to create an SSH key on our server, and give that key to GitHub as an input variable.
On the server, use the keygen utility to generate a new key.
ssh-keygen -t rsa -b 4096
Copy the content of the private key.
more ~/.ssh/id_rsa
Copy the contents of the file to the clipboard.
Caution
You should never share your SSH_PRIVATE_KEY with anyone, otherwise they will be able to access the server.
In addition, we will also add the public key to the authorized keys of our server.
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
Now reboot the server to update the keys.
sudo reboot
Go to your project's folder in GitHub and select the Settings tab.
In the sidebar on the left, open Secrets and variables, and select Actions.
Inside the GitHub Actions secrets and variables section, select New repository secret
Add secrets as Name Value pairs for:
- SSH_PRIVATE_KEY = The private key's copy we just copied to the clipboard.
- SSH_USER = The name of the user you log into the VPS server with.
- SSH_HOST = IP address of your server.
- WORK_DIR = Directory containing our docker-compose.yml file, using the absolute path
/home/edward/react-counter.
Inside your project folder on your local computer, push your changes to the repository.
Add your changes to the git staging area.
git add .
Commit your changes.
git commit -m feat: deploy
Push your changes to the repository.
git push
Go to your project's folder in GitHub and select the workflows tab.
You should see a new workflow running where the workflow triggers a publish image and deploy image workflow.
Tip
If in the deploy image step you have an error Connection closed by remote host restart your server.
sudo rebootYou should be able to log back into the server normally in a short while.
Now rerun the failed job deploy image again.
This setup uses Docker's networking feature to communicate with containers and Nginx's reverse proxy feature to protect containers from the public facing internet.
When creating and publishing new Docker containers with .yml files, be sure to include the following information in your docker-compose.yml file to ensure that Nginx can commmunicate with your container:
# Template: Hello World
# Description: A test container that displays a simple "Hello, World!" message in the browser.
services:
hello-world: # Use the service name as the container name
container_name: hello-world # Use the service name as the container name
image: crccheck/hello-world
environment:
VIRTUAL_HOST: hello-world.monatemedia.com # Tell nginx-proxy to route traffic based on the service name eg. hello-world.monatemedia.com
LETSENCRYPT_HOST: hello-world.monatemedia.com # Enable Let's Encrypt SSL for this domain
VIRTUAL_PORT: 8000 # Tell nginx-proxy that the container serves on port 8000
networks:
- proxy-network
networks:
proxy-network:
external: trueDo not forget to create a DNS record for your container to be reached at the desired website address, as provided in the VIRTUAL_HOST for unsecured HTTP on port 80, and LETSENCRYPT_HOST for secured HTTPS on port 443. All three should be the same.
For more examples, please refer to the Documentation
- Node
docker-compose.ymlscript - PHP Laravel
docker-compose.ymlscript - Python Scripts
- Django
docker-compose.ymlscript - Streamlit
docker-compose.ymlscript
- Django
See the open issues for a full list of proposed features (and known issues).
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Distributed under the MIT License. See LICENSE.txt for more information.
Monate Media - @MonateMedia - edward@monatemedia.com
Project Link: https://github.com/monatemedia/docker-engine-on-linux
- Othneil Drew Starter README Template
- Ileriayo Adebiyi Markdown Badges
- Programonaut How To Easily Set Up A Server (VPS) For Your Side Projects
- Programonaut How To Host An Application On A Server (VPS) Using Docker?
- Programonaut How To Set Up A Domain For Your Application!
- Programonaut How To Set Up A Reverse Proxy With Free SSL Using Nginx-Proxy
- Django Road Deploying Django with Docker Compose, Gunicorn and Nginx


