{"id":2417,"date":"2024-06-02T17:08:23","date_gmt":"2024-06-02T14:08:23","guid":{"rendered":"https:\/\/www.fibacloud.com\/community\/tutorials\/?p=2417"},"modified":"2026-10-04T22:57:46","modified_gmt":"2026-10-04T19:57:46","slug":"how-to-deploy-an-application-with-docker-docker-installation-and-management","status":"publish","type":"post","link":"https:\/\/www.fibacloud.com\/community\/tutorials\/en\/how-to-deploy-an-application-with-docker-docker-installation-and-management\/","title":{"rendered":"Install Docker and Deploy an App on Ubuntu"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"2417\" class=\"elementor elementor-2417\" data-elementor-post-type=\"post\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2a81909 e-con-full e-flex e-con e-parent\" data-id=\"2a81909\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5f686ae elementor-widget elementor-widget-text-editor\" data-id=\"5f686ae\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<style>\/*! elementor - v3.21.0 - 08-05-2024 *\/\n.elementor-widget-text-editor.elementor-drop-cap-view-stacked .elementor-drop-cap{background-color:#69727d;color:#fff}.elementor-widget-text-editor.elementor-drop-cap-view-framed .elementor-drop-cap{color:#69727d;border:3px solid;background-color:transparent}.elementor-widget-text-editor:not(.elementor-drop-cap-view-default) .elementor-drop-cap{margin-top:8px}.elementor-widget-text-editor:not(.elementor-drop-cap-view-default) .elementor-drop-cap-letter{width:1em;height:1em}.elementor-widget-text-editor .elementor-drop-cap{float:left;text-align:center;line-height:1;font-size:50px}.elementor-widget-text-editor .elementor-drop-cap-letter{display:inline-block}<\/style>\t\t\t\t<p>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 <strong>Docker Engine and one static web application on a new Ubuntu 24.04 LTS server<\/strong>.<\/p>\n<figure class=\"fc-editorial-figure\" data-fc-visual=\"20260920\" aria-labelledby=\"fc-editorial-caption-2417\"><a href=\"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-content\/uploads\/community-editorial-20260920\/fc-docker-en-inline-20260920.webp\" target=\"_blank\" rel=\"noopener\" aria-label=\"Open full-size illustration\"><picture><source media=\"(max-width: 600px)\" srcset=\"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-content\/uploads\/community-editorial-20260920\/fc-docker-en-mobile-20260920.webp\" width=\"720\" height=\"1140\"><img loading=\"lazy\" src=\"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-content\/uploads\/community-editorial-20260920\/fc-docker-en-inline-20260920.webp\" srcset=\"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-content\/uploads\/community-editorial-20260920\/fc-docker-en-inline-20260920.webp 1440w, https:\/\/www.fibacloud.com\/community\/tutorials\/wp-content\/uploads\/community-editorial-20260920\/fc-docker-en-inline-20260920-300x242.webp 300w, https:\/\/www.fibacloud.com\/community\/tutorials\/wp-content\/uploads\/community-editorial-20260920\/fc-docker-en-inline-20260920-1024x825.webp 1024w, https:\/\/www.fibacloud.com\/community\/tutorials\/wp-content\/uploads\/community-editorial-20260920\/fc-docker-en-inline-20260920-768x619.webp 768w\" sizes=\"auto, (max-width: 900px) 100vw, 820px\" width=\"1440\" height=\"1160\" alt=\"Images, containers and persistent data\" class=\"wp-image-2578\"  decoding=\"async\"><\/picture><\/a><figcaption id=\"fc-editorial-caption-2417\"><strong>Images, containers and persistent data<\/strong> An image packages an application for execution. Multiple containers can use the same image. Persistent data lives in a volume outside a container\u2019s writable layer.<details><summary>Step-by-step explanation<\/summary><ol><li>Build: Create an image from source and Dockerfile.<\/li><li>Ship: Push a versioned image to a registry.<\/li><li>Run: Start containers from the same image.<\/li><li>Persist: Store data in a separate volume.<\/li><\/ol><\/details><\/figcaption><\/figure>\n<h2>Before you begin<\/h2>\n<p>You need a sudo-capable account, sufficient disk space and access to Docker&#8217;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.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e046ea5 elementor-widget elementor-widget-text-editor\" data-id=\"e046ea5\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<pre><code class=\"language-bash\">cat \/etc\/os-release\ndpkg --print-architecture\ndf -h \/var\/lib\nsudo ss -ltnp '( sport = :8080 )'<\/code><\/pre>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1effa0b elementor-widget elementor-widget-text-editor\" data-id=\"1effa0b\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>The examples use <code>sudo<\/code>. Membership in the <code>docker<\/code> 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.<\/p>\n<h2>1. Install Docker Engine from its official repository<\/h2>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b014e7b elementor-widget elementor-widget-text-editor\" data-id=\"b014e7b\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<pre><code class=\"language-bash\">sudo apt update\nsudo apt install ca-certificates curl\nsudo install -m 0755 -d \/etc\/apt\/keyrings\nsudo curl -fsSL https:\/\/download.docker.com\/linux\/ubuntu\/gpg -o \/etc\/apt\/keyrings\/docker.asc\nsudo chmod a+r \/etc\/apt\/keyrings\/docker.asc\nsudo tee \/etc\/apt\/sources.list.d\/docker.sources &gt; \/dev\/null &lt;&lt;EOF\nTypes: deb\nURIs: https:\/\/download.docker.com\/linux\/ubuntu\nSuites: $(. \/etc\/os-release &amp;&amp; echo \"${UBUNTU_CODENAME:-$VERSION_CODENAME}\")\nComponents: stable\nArchitectures: $(dpkg --print-architecture)\nSigned-By: \/etc\/apt\/keyrings\/docker.asc\nEOF\nsudo apt update\napt-cache policy docker-ce\nsudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin<\/code><\/pre>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4a14efd elementor-widget elementor-widget-text-editor\" data-id=\"4a14efd\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>If <code>docker.sources<\/code> is already managed, inspect it before overwriting it. Verify that the package origin is Docker&#8217;s official repository and record the installed version. This is an Ubuntu workflow, not an RPM-distribution recipe.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-403b152 elementor-widget elementor-widget-text-editor\" data-id=\"403b152\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<pre><code class=\"language-bash\">sudo systemctl status docker --no-pager\nsudo docker version\nsudo docker run --rm hello-world<\/code><\/pre>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b599a5a elementor-widget elementor-widget-text-editor\" data-id=\"b599a5a\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p><code>hello-world<\/code> checks image retrieval and basic execution. It does not validate your application&#8217;s access controls, persistent data or rollback process.<\/p>\n<h2>2. Prepare the application and record its image<\/h2>\n<p>Create a new working directory and static page:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9e9c920 elementor-widget elementor-widget-text-editor\" data-id=\"9e9c920\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<pre><code class=\"language-bash\">mkdir -p fc-docker-demo\/site\ncd fc-docker-demo\nprintf '%s\\n' '&lt;!doctype html&gt;&lt;html lang=\"en\"&gt;&lt;title&gt;Docker test&lt;\/title&gt;&lt;h1&gt;Container OK&lt;\/h1&gt;&lt;\/html&gt;' &gt; site\/index.html\nsudo docker pull nginx:stable-alpine\nFC_IMAGE=\"$(sudo docker image inspect nginx:stable-alpine --format '{{index .RepoDigests 0}}')\"\nprintf '%s\\n' \"$FC_IMAGE\" &gt; image-digest.txt<\/code><\/pre>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0c84e0a elementor-widget elementor-widget-text-editor\" data-id=\"0c84e0a\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p><code>stable-alpine<\/code> 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.<\/p>\n<h2>3. Run with a local port and resource limits<\/h2>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a230b1f elementor-widget elementor-widget-text-editor\" data-id=\"a230b1f\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<pre><code class=\"language-bash\">sudo docker run -d --name fc-web-demo \\\n  --restart unless-stopped \\\n  --memory 128m --cpus 0.50 --pids-limit 128 \\\n  --security-opt no-new-privileges:true \\\n  --read-only \\\n  --tmpfs \/var\/cache\/nginx:rw,noexec,nosuid,size=32m \\\n  --tmpfs \/var\/run:rw,noexec,nosuid,size=1m \\\n  --tmpfs \/tmp:rw,noexec,nosuid,size=8m \\\n  -p 127.0.0.1:8080:80 \\\n  -v \"$PWD\/site:\/usr\/share\/nginx\/html:ro\" \\\n  \"$FC_IMAGE\"<\/code><\/pre>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-55cefac elementor-widget elementor-widget-text-editor\" data-id=\"55cefac\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>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.<\/p>\n<p><code>127.0.0.1:8080:80<\/code> publishes only on the server&#8217;s loopback address. In contrast, <code>-p 80:80<\/code> can expose the service on all host interfaces and conflict with another web server. Docker&#8217;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.<\/p>\n<h2>4. Verify responses, logs and access boundaries<\/h2>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-25b0a04 elementor-widget elementor-widget-text-editor\" data-id=\"25b0a04\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<pre><code class=\"language-bash\">sudo docker ps --filter name=fc-web-demo\nsudo docker logs --tail 50 fc-web-demo\ncurl --fail http:\/\/127.0.0.1:8080\/\nsudo docker inspect fc-web-demo --format '{{.HostConfig.Memory}} {{.HostConfig.NanoCpus}}'\nsudo docker stats --no-stream fc-web-demo<\/code><\/pre>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7c14b02 elementor-widget elementor-widget-text-editor\" data-id=\"7c14b02\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>The page should contain <code>Container OK<\/code>. Memory and CPU settings should not be unlimited. From another machine, direct access to port 8080 on the server&#8217;s public address should fail. To inspect the application remotely, open a tunnel from your own computer:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a42dcf8 elementor-widget elementor-widget-text-editor\" data-id=\"a42dcf8\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<pre><code class=\"language-bash\">ssh -N -L 8080:127.0.0.1:8080 user@server-address<\/code><\/pre>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2ce00c4 elementor-widget elementor-widget-text-editor\" data-id=\"2ce00c4\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>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.<\/p>\n<h2>5. Handle updates, persistent data and rollback<\/h2>\n<p>This static example stores its content in the host&#8217;s <code>site<\/code> directory. Do not leave databases or user uploads in a container&#8217;s disposable writable layer. A volume is not a backup: take application-consistent backups and prove restoration in another environment.<\/p>\n<p>Start the new image with another container name and a separate binding such as <code>127.0.0.1:8081:80<\/code>. 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.<\/p>\n<p>Remove only this example when finished:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1798d9a elementor-widget elementor-widget-text-editor\" data-id=\"1798d9a\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<pre><code class=\"language-bash\">sudo docker stop fc-web-demo\nsudo docker rm fc-web-demo<\/code><\/pre>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-862e035 elementor-widget elementor-widget-text-editor\" data-id=\"862e035\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Do not make host-wide commands such as <code>docker system prune --volumes<\/code> a routine rollback step.<\/p>\n<h2>Troubleshooting<\/h2>\n<p><strong>Port occupied:<\/strong> identify the listener with <code>ss<\/code> or change the local example port. <strong>Permission denied:<\/strong> inspect file and group permissions instead of making the Docker socket world-writable. <strong>Container exits:<\/strong> inspect its logs and exit code, including possible memory-limit termination. <strong>Image pull fails:<\/strong> investigate DNS, TLS and registry connectivity before changing to an unverified mirror.<\/p>\n<h2>Official references<\/h2>\n<ul>\n<li><a href=\"https:\/\/docs.docker.com\/engine\/install\/ubuntu\/\" rel=\"nofollow noopener\" target=\"_blank\">Install Docker Engine on Ubuntu<\/a><\/li>\n<li><a href=\"https:\/\/docs.docker.com\/engine\/network\/port-publishing\/\" rel=\"nofollow noopener\" target=\"_blank\">Port publishing and localhost binding<\/a><\/li>\n<li><a href=\"https:\/\/docs.docker.com\/engine\/containers\/resource_constraints\/\" rel=\"nofollow noopener\" target=\"_blank\">Container CPU and memory constraints<\/a><\/li>\n<li><a href=\"https:\/\/docs.docker.com\/engine\/network\/packet-filtering-firewalls\/\" rel=\"nofollow noopener\" target=\"_blank\">Docker packet filtering and firewalls<\/a><\/li>\n<\/ul>\n<p class=\"fc-article-review-date\">Technical content and sources reviewed on October 4, 2026. Recheck the relevant official documentation when a version or provider changes.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Install Docker on Ubuntu 24.04, record image digests, use local ports and resource limits, verify the application and plan rollback.<\/p>\n","protected":false},"author":1,"featured_media":2577,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[259,257,261],"class_list":["post-2417","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials-en","tag-application","tag-container","tag-docker"],"lang":"en","translations":{"en":2417,"tr":1944},"pll_sync_post":[],"_links":{"self":[{"href":"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-json\/wp\/v2\/posts\/2417","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-json\/wp\/v2\/comments?post=2417"}],"version-history":[{"count":17,"href":"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-json\/wp\/v2\/posts\/2417\/revisions"}],"predecessor-version":[{"id":2434,"href":"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-json\/wp\/v2\/posts\/2417\/revisions\/2434"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-json\/wp\/v2\/media\/2577"}],"wp:attachment":[{"href":"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-json\/wp\/v2\/media?parent=2417"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-json\/wp\/v2\/categories?post=2417"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fibacloud.com\/community\/tutorials\/wp-json\/wp\/v2\/tags?post=2417"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}