Table of Contents
For this project I am using an Ubuntu 24.04 server.
Creating the app
Prepare server
First we will need to prepare the server, for the app development
First we Update and Upgrade out Ubuntu server
sudo apt update && sudo apt upgrade
When the update is finished, you’ll need to install Python, and a few extra packages
sudo apt update && sudo apt install -y python3 python3-pip
You can check the versions of Python and Pip like this:
python3 --version
pip --version
Creating our project directory
First we will create the directory for our project
mkdir flask_project
cd flask_project
After that’s done, we want to create a virtual environment. It’s always recommended to create a virtual environment when working with Python. It helps to avoid any conflicts and makes it easy to share the project with all required dependencies.
python3 -m venv venv # Creates the virtual environment
source venv/bin/activate # Activates the virtual environment (venv)
Installing modules
For the project I am making, I need to install “Flask”, “Flask SQLAlchemy” and “ping3” – you might only need “Flask”, if you are not doing the same project as me.
pip install flask flask_sqlalchemy ping3
You can check the modules you have installed by running:
pip list
Creating the Python code
First, start by creating a file named “app.py” – this is where we will write our code.
Make sure that you are in the right folder (the one from earlier “flask_project”)
nano app.py
Insert the code (don’t mind the danish comments, as this is used for my school project also, I will change it later)
from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from ping3 import ping
import os # Bruges til at arbejde med file paths
# Initialiserer Flask Applikationen
app = Flask(__name__)
# Først bliver der defineret hvor SQL-Lite databasen skal gemmes
db_path = os.path.join(os.getcwd(), "serverips.db")
app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{db_path}"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
# Initialiserer databasen
db = SQLAlchemy(app)
# Opretter en table i databasen
class Server(db.Model):
# Laver ID, Name og en kolonne til IP adresser
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
ip = db.Column(db.String(100), unique=True, nullable=False)
# Opretter databasen, hvis den ikke findes i forvejen
with app.app_context():
db.create_all()
# Definere en URL-sti for hjemmesiden
@app.route("/")
def home():
# Henter alle servere fra databasen
servers = Server.query.all()
# Laver en tom liste til at holde server status
server_status = []
# For hver server, bliver der lavet en dictionary og det bliver derefter tilføjet til listen
for server in servers:
server_dict = {
"id": server.id,
"name": server.name,
"ip": server.ip,
"status": check_server_status(server.ip)
}
server_status.append(server_dict)
# Sender de hentede servere til HTML og viser HTML siden
return render_template("index.html", servers=server_status)
@app.route("/add", methods=["POST"])
def add_server():
# Henter data fra formular
name = request.form["name"]
ip = request.form["ip"]
# Opretter ny server
new_server = Server(name=name, ip=ip)
# Gemmer serveren i databasen
db.session.add(new_server)
db.session.commit()
# Redirect brugeren til hjemmesiden
return redirect(url_for("home"))
@app.route("/delete/<int:server_id>", methods=["POST"])
def delete_server(server_id):
# Finder serveren i databasen
server = Server.query.get(server_id)
# Sletter serveren
if server:
db.session.delete(server)
db.session.commit()
# Redirect brugeren til hjemmesiden
return redirect(url_for("home"))
def check_server_status(ip):
# Prøver at ping en server, og retunere den status fra ping
try:
# Pinger serveren med timeout på 1 sekund
response = ping(ip, timeout=1)
return "ONLINE" if response else "OFFLINE"
except Exception:
# Hvis ping fejler, bliver den returneret som offline
return "OFFLINE"
# Hvis filen køres direkte, så eksekveres koden herunder
if __name__ == "__main__":
# Kører Flask serveren i debug mode, den acceptere forbindelser på alle IP-adresser, og lytter på port 5000
app.run(debug=True, host="0.0.0.0", port=5000)
Creating the HTML page
In the code above, I’m referring to an HTML document in the folder “templates”. We need to first create this folder, and create the HMTL document inside.
First create the folder “templates”
mkdir templates
Now create and edit the a file named “index.html”
nano index.html
I made some HTML code to display with the APP
<!DOCTYPE html>
<html lang="da">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Server Status</title>
<style>
.online { color: green; font-weight: bold; }
.offline { color: red; font-weight: bold; }
</style>
<script>
function updateStatus() {
fetch('/status')
.then(response => response.json())
.then(data => {
data.forEach(server => {
let row = document.getElementById("server-" + server.id);
if (row) {
let statusCell = row.querySelector(".status");
statusCell.innerText = server.status;
statusCell.className = "status " + (server.status === "ONLINE" ? "online" : "offline");
}
});
})
.catch(error => console.error('Fejl ved opdatering:', error));
}
setInterval(updateStatus, 10000); // Opdatering hvert 10. sekund
</script>
</head>
<body>
<h1>Server Status</h1>
<table border="1">
<tr>
<th>Servernavn</th>
<th>IP-adresse</th>
<th>Status</th>
<th>Handling</th>
</tr>
{% for server in servers %}
<tr id="server-{{ server.id }}">
<td>{{ server.name }}</td>
<td>{{ server.ip }}</td>
<td class="status {{ 'online' if server.status == 'ONLINE' else 'offline' }}">
{{ server.status }}
</td>
<td>
<form action="/delete/{{ server.id }}" method="POST" style="display:inline;">
<button type="submit">Slet</button>
</form>
</td>
</tr>
{% endfor %}
</table>
<h2>Tilføj en ny server</h2>
<form action="/add" method="POST">
<label for="name">Servernavn:</label>
<input type="text" id="name" name="name" required>
<br><br>
<label for="ip">IP-adresse:</label>
<input type="text" id="ip" name="ip" required>
<br><br>
<button type="submit">Tilføj server</button>
</form>
</body>
</html>
Testing the APP
To test the app after you have added all the code, simply run the following code, make sure, that you are in the right directory first.
python3 app.py
Go to http://serverip:5000 – you should see the HTML page and be able to add and remove servers you want to monitor. There will also be and “ONLINE” or “OFFLINE” status on all the servers.
Building the APP as a Docker Container
You can create this app as a Docker Container in a few easy steps
Installing Docker
Run the following script, make sure to have curl installed first
curl -fsSL https://get.docker.com | sudo bash
Create a Dockerfile
Make sure you are still in the project directory
nano Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
Create the requirements.txt file
nano requirements.txt
flask
flask_sqlalchemy
ping3
Create docker-compose.yml file
nano docker-compose.yml
version: '3.8'
services:
flask-app:
build: .
container_name: flask-server
restart: always
volumes:
- sqlite_data:/app
ports:
- "5000:5000"
volumes:
sqlite_data:
Build and run the Container
docker build -t flask-server .
docker run -d -p 5000:5000 --name flask-app flask-server
Pushing Container to Docker Hub
docker build -t <your_username>/flask-server:latest .
docker login -u <your_username>
docker push <your_username>/flask-server:latest
Pulling and running the Image on another server
docker pull <your_username>/flask-server:latest
docker run -d -p 5000:5000 --name flask-app <your_username>/flask-server:latest