|
| 1 | +--- |
| 2 | +id: deploy-applications-with-dokploy |
| 3 | +title: Deploy Applications with Dokploy |
| 4 | +tags: [devops, ci, cd, cicd, dokploy, paas, ecs, docker, swarm, gitops] |
| 5 | +sidebar_position: 3 |
| 6 | +--- |
| 7 | + |
| 8 | +# Deploy Applications with Dokploy |
| 9 | + |
| 10 | +The final part of this blueprint describes how to deploy highly available user workloads with Dokploy on Open Telekom Cloud, positioning it as an open-source alternative to platforms such as Vercel, Netlify, Azure App Services and AWS Elastic Beanstalk. |
| 11 | + |
| 12 | +Before we deploy any application with Dokploy we first need to create a Project. Go to *Dokploy Console* -> *Home* -> *Projects* and click *Create Project*, give it a name and click *Create*. |
| 13 | + |
| 14 | +## Deploying a Docker Stack |
| 15 | + |
| 16 | +### Simple Application |
| 17 | + |
| 18 | +Open the created project and click *Create Service* -> *Docker Compose*. Fill in the **Name**, in this case `whoami` as we are going to install the `traefik/whoami` application, a Go server that prints OS information and HTTP request to output. Choose `Stack` as **Compose Type** and click *Create*: |
| 19 | + |
| 20 | + |
| 21 | + |
| 22 | +Go to *General* and disable *Auto-deploy*, click *Raw*, paste the following YAML in the text area and click *Save*: |
| 23 | + |
| 24 | +```yaml |
| 25 | +version: "3.8" |
| 26 | +services: |
| 27 | + whoami: |
| 28 | + image: containous/whoami:v1.5.0 |
| 29 | + deploy: |
| 30 | + replicas: 1 |
| 31 | +``` |
| 32 | +
|
| 33 | +Go to *Domains* and click *Add Domain*. Select the service, in this case there is only one, namely `whoami`, from the **Service Name** drop-box and set **Container Port** to `80` (that should always be the port that container is listening to and not a custom one that you would like to expose the service to). |
| 34 | + |
| 35 | +:::important |
| 36 | +Keep **HTTPS** disabled because TLS is terminated at the Elastic Load Balancer. |
| 37 | +::: |
| 38 | + |
| 39 | + |
| 40 | + |
| 41 | +Next, define the **Host** URL. You can choose between a testing address or one intended for production workloads. Clicking the *dice button* on the right, generates a random URL from the traefik.me service and sets it as your **Host**. This is suitable for testing, as it does not support SSL certificates. |
| 42 | + |
| 43 | + |
| 44 | + |
| 45 | +:::note |
| 46 | +[Traefik.me](https://traefik.me/) is a wildcard DNS service, similar to nip.io or xip.io, that resolves any IP address. |
| 47 | +::: |
| 48 | + |
| 49 | +For production, you can use `whoami.dokploy.example.com`, assuming that `dokploy.example.com` was configured as the Web Server Domain Address in the earlier steps. |
| 50 | + |
| 51 | +Finally, click *Create*, go back to *General*, and select *Deploy*. If the configuration is correct, your workload will be deployed on the worker nodes of the swarm and both endpoints should now be accessible: |
| 52 | + |
| 53 | + |
| 54 | + |
| 55 | +:::note |
| 56 | +Applications under your domain are secure because TLS is terminated at the ELB with a wildcard certificate that covers `*.dokploy.example.com`. When a user visits any app like `whoami.dokploy.example.com`, the certificate’s SAN matches the hostname, the chain validates, and the browser marks the session as secure. |
| 57 | +::: |
| 58 | + |
| 59 | +### Multi-Service Application |
| 60 | + |
| 61 | +The previous example was simplified. Next, we will demonstrate how to deploy a Docker stack with multiple interdependent services that require more advanced configuration. Open the created project and click *Create Service* -> *Docker Compose*. Fill in the **Name**, in this case `typesense`, choose `Stack` as **Compose Type** and click *Create*. In this example we are going to deploy the following services: |
| 62 | + |
| 63 | +- A single-node [Typesense](https://typesense.org/) server. |
| 64 | +- A [Typesense Dashboard](https://github.com/bfritscher/typesense-dashboard) to manage and browse collections. |
| 65 | +- A [Typesense DocSearch Scraper](https://github.com/typesense/typesense-docsearch-scraper), customized to index data in Typesense from an external [Docusaurus](https://docusaurus.io/) site. |
| 66 | +- A [Docker Job Scheduler](https://github.com/mcuadros/ofelia) that will trigger the scraper every 5 minutes. |
| 67 | + |
| 68 | +Go to *General* and disable *Auto-deploy*, click *Raw*, paste the following YAML in the text area and click *Save*: |
| 69 | + |
| 70 | +```yaml |
| 71 | +version: '3.8' |
| 72 | +
|
| 73 | +services: |
| 74 | + typesense: |
| 75 | + image: typesense/typesense:30.0.rc10 |
| 76 | + networks: |
| 77 | + - dokploy-network |
| 78 | + volumes: |
| 79 | + - typesense-data:/data |
| 80 | + environment: |
| 81 | + TYPESENSE_API_KEY: ${TYPESENSE_API_KEY} |
| 82 | + TYPESENSE_DATA_DIR: /data |
| 83 | + TYPESENSE_ENABLE_CORS: "true" |
| 84 | +
|
| 85 | + dashboard: |
| 86 | + image: bfritscher/typesense-dashboard |
| 87 | + networks: |
| 88 | + - dokploy-network |
| 89 | + environment: |
| 90 | + VITE_AUTH_ENABLED: "false" |
| 91 | +
|
| 92 | + docsearch-scraper: |
| 93 | + image: typesense/docsearch-scraper:0.12.0.rc13 |
| 94 | + networks: |
| 95 | + - dokploy-network |
| 96 | + deploy: |
| 97 | + replicas: 1 |
| 98 | + placement: |
| 99 | + constraints: |
| 100 | + - node.role == worker |
| 101 | + depends_on: |
| 102 | + - typesense |
| 103 | + environment: |
| 104 | + CONFIG: | |
| 105 | + { |
| 106 | + "index_name": "${SCRAPER_COLLECTION_INDEX}", |
| 107 | + "start_urls": [ |
| 108 | + "https://${SCRAPER_TARGET_HOST}/" |
| 109 | + ], |
| 110 | + "sitemap_urls": [ |
| 111 | + "https://${SCRAPER_TARGET_HOST}/sitemap.xml" |
| 112 | + ], |
| 113 | + "sitemap_alternate_links": true, |
| 114 | + "stop_urls": [ |
| 115 | + "/tests" |
| 116 | + ], |
| 117 | + "selectors": { |
| 118 | + "lvl0": { |
| 119 | + "selector": "(//ul[contains(@class,'menu__list')]//a[contains(@class, 'menu__link menu__link--sublist menu__link--active')]/text() | //nav[contains(@class, 'navbar')]//a[contains(@class, 'navbar__link--active')]/text())[last()]", |
| 120 | + "type": "xpath", |
| 121 | + "global": true, |
| 122 | + "default_value": "Documentation" |
| 123 | + }, |
| 124 | + "lvl1": "header h1", |
| 125 | + "lvl2": "article h2", |
| 126 | + "lvl3": "article h3", |
| 127 | + "lvl4": "article h4", |
| 128 | + "lvl5": "article h5, article td:first-child", |
| 129 | + "lvl6": "article h6", |
| 130 | + "text": "article p, article li, article td:last-child" |
| 131 | + }, |
| 132 | + "strip_chars": " .,;:#", |
| 133 | + "custom_settings": { |
| 134 | + "separatorsToIndex": "_", |
| 135 | + "attributesForFaceting": [ |
| 136 | + "language", |
| 137 | + "version", |
| 138 | + "type", |
| 139 | + "docusaurus_tag" |
| 140 | + ], |
| 141 | + "attributesToRetrieve": [ |
| 142 | + "hierarchy", |
| 143 | + "content", |
| 144 | + "anchor", |
| 145 | + "url", |
| 146 | + "url_without_anchor" |
| 147 | + ] |
| 148 | + }, |
| 149 | + "conversation_id": [ |
| 150 | + "833762294" |
| 151 | + ], |
| 152 | + "nb_hits": 46250 |
| 153 | + } |
| 154 | + TYPESENSE_API_KEY: ${TYPESENSE_API_KEY} |
| 155 | + TYPESENSE_HOST: typesense |
| 156 | + TYPESENSE_PORT: 8108 |
| 157 | + TYPESENSE_PROTOCOL: http |
| 158 | + SCRAPER_TARGET_HOST: ${SCRAPER_TARGET_HOST} |
| 159 | + SCRAPER_COLLECTION_INDEX: ${SCRAPER_COLLECTION_INDEX} |
| 160 | + REQUEST_FINGERPRINTER_IMPLEMENTATION: "2.7" |
| 161 | + command: python3 /app/src/docsearch.py |
| 162 | + restart: no |
| 163 | +
|
| 164 | + scheduler: |
| 165 | + image: mcuadros/ofelia:latest |
| 166 | + networks: |
| 167 | + - dokploy-network |
| 168 | + depends_on: |
| 169 | + - docsearch-scraper |
| 170 | + command: daemon --docker |
| 171 | + volumes: |
| 172 | + - /var/run/docker.sock:/var/run/docker.sock:ro |
| 173 | + labels: |
| 174 | + ofelia.job-run.docsearch-scraper.schedule: "@every 5m" |
| 175 | + ofelia.job-run.docsearch-scraper.container: "docsearch-scraper" |
| 176 | + restart: unless-stopped |
| 177 | +
|
| 178 | +volumes: |
| 179 | + typesense-data: |
| 180 | +``` |
| 181 | + |
| 182 | +:::note |
| 183 | +Notice that we have introduced two new configuration properties in the YAML file: |
| 184 | + |
| 185 | +- `networks`: All containers are placed in the same Docker network, allowing them to communicate with each other internally without interruption. |
| 186 | +- `deploy.placement.constrains`: We explicitly specify the node group where containers are deployed. This ensures that manager nodes are not overloaded with user workloads and allows future separation of workloads by introducing specialized worker pools, such as GPU or ARM-based nodes. |
| 187 | + |
| 188 | +::: |
| 189 | + |
| 190 | +Next thing you need to do is set the environment variables required on project, environment or service level. For more details on how Dokploy is handling enviroment variables see [Environment Variables](https://docs.dokploy.com/docs/core/variables) in the official Dokploy documentation. |
| 191 | + |
| 192 | + |
| 193 | + |
| 194 | +Then, go to *Domains* and create 2 domains. One for the **typesense** service (set **Container Port** to 8108), and one for the **typesense-dashboard** service ((set **Container Port** to 8108). |
| 195 | + |
| 196 | + |
| 197 | + |
| 198 | +If the configuration is correct, all containers should be deployed on the worker nodes of the swarm and we could now visit the dashboard endpoint and observe our search engine collections and indices getting populated: |
| 199 | + |
| 200 | + |
| 201 | + |
| 202 | +## Deploying from a Dokploy Template |
| 203 | + |
| 204 | +The Dokploy template library provides a collection of preconfigured application stacks that can be deployed with minimal setup. Templates cover common services such as databases, monitoring tools, and developer utilities, offering sensible defaults that reduce configuration effort and errors. They can be used directly for quick deployments or extended with custom settings for production environments. Teams may also add their own templates to the library to standardize and simplify application delivery across projects. |
| 205 | + |
| 206 | + |
| 207 | + |
| 208 | +:::warning |
| 209 | +Most templates in the Dokploy library are designed for single-server setups. When running on Docker Swarm, you **may** need to adjust them to ensure they work reliably in a clustered environment. |
| 210 | +::: |
| 211 | + |
| 212 | +<!-- ## Building and Deploying from a Git Repo --> |
0 commit comments