
Docker packages an application and its dependencies into an image that runs in a container. Isolation is useful, but containers have no default CPU or memory limits and do not automatically provide backups or high availability. This guide covers Docker Engine and one static web application on a new Ubuntu 24.04 LTS server.

Step-by-step explanation
- Build: Create an image from source and Dockerfile.
- Ship: Push a versioned image to a registry.
- Run: Start containers from the same image.
- Persist: Store data in a separate volume.
Before you begin
You need a sudo-capable account, sufficient disk space and access to Docker’s official package repository. If Docker, Podman, Kubernetes or a control panel is already installed, review the upgrade and conflicting-package documentation instead of removing packages indiscriminately. This example does not configure a production cluster, rootless Docker or multi-server orchestration.
cat /etc/os-release
dpkg --print-architecture
df -h /var/lib
sudo ss -ltnp '( sport = :8080 )' The examples use sudo. Membership in the docker group can grant root-level privileges and should not be treated as a harmless convenience. Complete package, network and container acceptance checks on a separate test server.
1. Install Docker Engine from its official repository
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
apt-cache policy docker-ce
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin If docker.sources is already managed, inspect it before overwriting it. Verify that the package origin is Docker’s official repository and record the installed version. This is an Ubuntu workflow, not an RPM-distribution recipe.
sudo systemctl status docker --no-pager
sudo docker version
sudo docker run --rm hello-world hello-world checks image retrieval and basic execution. It does not validate your application’s access controls, persistent data or rollback process.
2. Prepare the application and record its image
Create a new working directory and static page:
mkdir -p fc-docker-demo/site
cd fc-docker-demo
printf '%s\n' '<!doctype html><html lang="en"><title>Docker test</title><h1>Container OK</h1></html>' > site/index.html
sudo docker pull nginx:stable-alpine
FC_IMAGE="$(sudo docker image inspect nginx:stable-alpine --format '{{index .RepoDigests 0}}')"
printf '%s\n' "$FC_IMAGE" > image-digest.txt stable-alpine is a mutable tag. Run the exact image digest you pulled and retain that deployment record. Test a new digest before updating production rather than silently replacing the old record. Never bake passwords, API tokens or private keys into an image.
3. Run with a local port and resource limits
sudo docker run -d --name fc-web-demo \
--restart unless-stopped \
--memory 128m --cpus 0.50 --pids-limit 128 \
--security-opt no-new-privileges:true \
--read-only \
--tmpfs /var/cache/nginx:rw,noexec,nosuid,size=32m \
--tmpfs /var/run:rw,noexec,nosuid,size=1m \
--tmpfs /tmp:rw,noexec,nosuid,size=8m \
-p 127.0.0.1:8080:80 \
-v "$PWD/site:/usr/share/nginx/html:ro" \
"$FC_IMAGE" If the name is already in use, do not delete the existing container. Choose another test name or follow its established upgrade procedure. Website files are mounted read-only; Nginx receives limited temporary storage for runtime files. These settings are not universal application defaults: measure memory requirements and identify legitimate write locations.
127.0.0.1:8080:80 publishes only on the server’s loopback address. In contrast, -p 80:80 can expose the service on all host interfaces and conflict with another web server. Docker’s NAT and firewall rules can differ from UFW expectations; checking a UFW rule alone is insufficient. Review the documented localhost-publication limitations in older Docker versions as well.
4. Verify responses, logs and access boundaries
sudo docker ps --filter name=fc-web-demo
sudo docker logs --tail 50 fc-web-demo
curl --fail http://127.0.0.1:8080/
sudo docker inspect fc-web-demo --format '{{.HostConfig.Memory}} {{.HostConfig.NanoCpus}}'
sudo docker stats --no-stream fc-web-demo The page should contain Container OK. Memory and CPU settings should not be unlimited. From another machine, direct access to port 8080 on the server’s public address should fail. To inspect the application remotely, open a tunnel from your own computer:
ssh -N -L 8080:127.0.0.1:8080 user@server-address For public access, place an HTTPS reverse proxy or load balancer in front of the application. Validate the hostname, certificate renewal, proxy headers and health checks separately; installing Docker does not configure them automatically.
5. Handle updates, persistent data and rollback
This static example stores its content in the host’s site directory. Do not leave databases or user uploads in a container’s disposable writable layer. A volume is not a backup: take application-consistent backups and prove restoration in another environment.
Start the new image with another container name and a separate binding such as 127.0.0.1:8081:80. Switch the reverse proxy only after content, health and resource checks pass. Keep the old image digest and a compatible data backup. Restarting an old image alone may not reverse a database schema migration.
Remove only this example when finished:
sudo docker stop fc-web-demo
sudo docker rm fc-web-demo Do not make host-wide commands such as docker system prune --volumes a routine rollback step.
Troubleshooting
Port occupied: identify the listener with ss or change the local example port. Permission denied: inspect file and group permissions instead of making the Docker socket world-writable. Container exits: inspect its logs and exit code, including possible memory-limit termination. Image pull fails: investigate DNS, TLS and registry connectivity before changing to an unverified mirror.
Official references
- Install Docker Engine on Ubuntu
- Port publishing and localhost binding
- Container CPU and memory constraints
- Docker packet filtering and firewalls
Technical content and sources reviewed on October 4, 2026. Recheck the relevant official documentation when a version or provider changes.
Leave a Reply