<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Josef Strzibny</title>
    <description>The latest articles on DEV Community by Josef Strzibny (@strzibny).</description>
    <link>https://dev.to/strzibny</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F154689%2F89190986-4d70-4c80-8958-ef6407185146.jpeg</url>
      <title>DEV Community: Josef Strzibny</title>
      <link>https://dev.to/strzibny</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/strzibny"/>
    <language>en</language>
    <item>
      <title>Self-host SerpBear with Coolify</title>
      <dc:creator>Josef Strzibny</dc:creator>
      <pubDate>Thu, 02 Apr 2026 08:47:23 +0000</pubDate>
      <link>https://dev.to/serpapi/self-host-serpbear-with-coolify-569h</link>
      <guid>https://dev.to/serpapi/self-host-serpbear-with-coolify-569h</guid>
      <description>&lt;p&gt;Tracking organic positions on search engines is one of the main concerns of &lt;a href="https://serpapi.com/use-cases/seo" rel="noopener noreferrer"&gt;SEO&lt;/a&gt;. SerpBear is a SERP position tracking tool that will help you track how well you are doing in Google search. This post will take you through all the steps to start tracking your keywords with your own SerpBear instance on Coolify.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is SerpBear?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdn02fo1req3grn26po8q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdn02fo1req3grn26po8q.png" alt="SerpBear logo" width="319" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/towfiqi/serpbear" rel="noopener noreferrer"&gt;SerpBear&lt;/a&gt; is an Open Source &lt;strong&gt;search engine position tracker&lt;/strong&gt;. It allows you to track your or your competitors' keyword positions in Google and to also get notified of these changes. Some of the features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unlimited keywords:&lt;/strong&gt;  You can add as many domains and keywords to track as you want. SerpBear will use a 3rd-party API such as SerpApi for actual tracking behind the scenes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible scraping strategy:&lt;/strong&gt;  Choose your scraping strategy to control how many Google pages are checked for each domain. It's built to handle the Google's 2025 removal of the &lt;code&gt;num=100&lt;/code&gt;parameter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email notification:&lt;/strong&gt;  Get notified of all your keyword position changes via email with at the frequency of your choosing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keyword research:&lt;/strong&gt;  You have the option to do keyword research with the integration of Google Ads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Search Console:&lt;/strong&gt;  You can see the actual visit count and impressions for each keyword. Discover new keywords thanks to direct integration with Google Search Console.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exports:&lt;/strong&gt;  Export your domain keyword data in CSV files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to track your keywords, but don't want to use SerpBear, have a look how to do your custom &lt;a href="https://serpapi.com/blog/serp-tracking-api-create-a-whiltelabel-rank-tracker-app/" rel="noopener noreferrer"&gt;SERP tracking in JavaScript&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Coolify?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://coolify.io" rel="noopener noreferrer"&gt;Coolify&lt;/a&gt; is an Open Source &lt;strong&gt;Platform as a Service&lt;/strong&gt; (PaaS) that will help you self-host SerpBear or any other self-hostable software out there. You can also deploy applications, databases, and one-click services.&lt;/p&gt;

&lt;p&gt;I am assuming you already have Coolify installed on your server. If you don't, you can learn how to &lt;a href="https://serpapi.com/blog/how-to-start-self-hosting-with-coolify-4-vps/" rel="noopener noreferrer"&gt;deploy Coolify on any VPS&lt;/a&gt; or take advantage of Coolify Cloud version where you don't have to host Coolify yourself.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 We are going to deploy SerpBear 3.0 on Coolify 4.0. Coolify 4.0 is still beta software for the time being.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Signing up for SerpApi
&lt;/h2&gt;

&lt;p&gt;SerpApi is a service providing access to various SERP results with a simple API. SerpBear is free and open source software, but it uses SerpApi to do the heavy lifting of querying and parsing Google results. SerpBear cannot do this on its own due to the nature of managing proxies and solving CAPTCHAs, but you can still start with free searches to set everything up and see it working before committing to a paid plan.&lt;/p&gt;

&lt;p&gt;So first of all, &lt;a href="https://serpapi.com/users/sign_up" rel="noopener noreferrer"&gt;sign up for SerpApi&lt;/a&gt; and then note your private API key from &lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;serpapi.com/manage-api-key&lt;/a&gt; page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7msjg3kgrsq42hzuuj5v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7msjg3kgrsq42hzuuj5v.png" alt="SerpApi dashboard" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are going to use this API key from SerpBear, but you can also use it to integrating one the many SerpApi SDKs to build anything needing &lt;a href="https://serpapi.com" rel="noopener noreferrer"&gt;SERP API&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring DNS
&lt;/h2&gt;

&lt;p&gt;Head over to your domain registrar console and set the DNS A records for domains or subdomains you want to use for SerpBear:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;coolify.example.com -&amp;gt; 178.104.25.112
serpbear.example.com -&amp;gt; 178.104.25.112
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Choose "A" type records to directly connect a domain name or subdomain to the IP address (replace the values, the above is just an example). If you'll run SerpBear on the same host as Coolify, the IP address remains the same for both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding SerpBear
&lt;/h2&gt;

&lt;p&gt;If your Coolify instance is fully set up, it's time to add SerpBear. To run a new Coolify project head over to &lt;em&gt;Projects&lt;/em&gt; (from the left menu) and click on &lt;strong&gt;+ Add&lt;/strong&gt; next to the Projects headline. Give it a name and description.&lt;/p&gt;

&lt;p&gt;From Projects, click on &lt;strong&gt;+ Add Resource&lt;/strong&gt; next to your project name or select your project first and click on &lt;strong&gt;+ New&lt;/strong&gt; next to &lt;em&gt;Resources&lt;/em&gt;. From here, we can select &lt;strong&gt;Docker Compose Empty&lt;/strong&gt; under &lt;em&gt;Docker Based&lt;/em&gt; on the right:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fimetq2p3oc3qu5bp4if5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fimetq2p3oc3qu5bp4if5.png" alt="Coolify's New Resource page" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SerpBear provides Docker Compose configuration which Coolify supports. Since SerpBear uses SQLite to save SERP data, it's not necessary to spin up process-based databases and the Compose file is relatively simple:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  app:
    image: towfiqi/serpbear:latest
    # Build from source instead of pulling the image:
    # build: .
    restart: unless-stopped
    ports:
      - "${PORT:-3000}:3000"
    environment:
      - USER_NAME=${USER:-admin}
      - PASSWORD=${PASSWORD}
      - SECRET=${SECRET}
      - APIKEY=${APIKEY}
      - SESSION_DURATION=${SESSION_DURATION:-24}
      - NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
      # Optional: Google Search Console integration
      - SEARCH_CONSOLE_CLIENT_EMAIL=${SEARCH_CONSOLE_CLIENT_EMAIL:-}
      - SEARCH_CONSOLE_PRIVATE_KEY=${SEARCH_CONSOLE_PRIVATE_KEY:-}
    volumes:
      - serpbear_data:/app/data
    healthcheck:
      test: ["CMD-SHELL", "wget -qO- http://localhost:3000 || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 15s

volumes:
  serpbear_data:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The SerpBear service definition includes the official Docker image, container restart policy, ports, environment variables, volumes, and health check. The official guide suggests using the latest image (&lt;code&gt;towfiqi/serpbear:latest&lt;/code&gt;) which will let you update the application with &lt;strong&gt;Redeploy&lt;/strong&gt; at any later point, but you can choose a stable release to lock-in a particular version.&lt;/p&gt;

&lt;p&gt;The required environment variables reference variables like &lt;code&gt;{USER:-admin}&lt;/code&gt; and &lt;code&gt;{SECRET}&lt;/code&gt; which let us manage the environment directly from the Coolify admin interface. Notice that SerpBear also supports Google Search Console, so if you can obtain these credentials as well. Finally notice the &lt;code&gt;serpbear_data&lt;/code&gt; volume which is the future location of your SerpBear database.&lt;/p&gt;

&lt;p&gt;Paste the configuration above. Click &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Adding the new resource should take you to the resource configuration. Under &lt;em&gt;General&lt;/em&gt; we can change the resource name, under &lt;em&gt;Persistent Storages&lt;/em&gt; we can check our persistent volume, and finally under &lt;em&gt;Environment Variables&lt;/em&gt; we can go fill up the variables from the Compose file:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jygvw1jk4gh62y1hksp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jygvw1jk4gh62y1hksp.png" alt="Coolify configuration" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the list of environment variables we should fill in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;USER_NAME&lt;/code&gt;: The username you want to use to login to the app.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PASSWORD&lt;/code&gt;: The password you want to use to log in to the app.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SECRET&lt;/code&gt;: A secret key that will be used for encrypting 3rd party API keys &amp;amp; passwords.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;APIKEY&lt;/code&gt;: API key that will be used to access the app's API. This is not SerpApi account key!&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SESSION_DURATION&lt;/code&gt;: The duration(in hours) of the user's logged-in session.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NEXT_PUBLIC_APP_URL&lt;/code&gt;: The URL where your app is hosted and can be accessed like &lt;a href="https://serpbear.example.com" rel="noopener noreferrer"&gt;https://serpbear.example.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that every environment entry has its own &lt;strong&gt;Update&lt;/strong&gt; button and they won't be saved all at once. You can add the Google Search Console credentials if you have them, but they aren't necessary to start tracking your keywords with SerpApi.&lt;/p&gt;

&lt;p&gt;Restart the service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tracking keywords with SerpBear
&lt;/h2&gt;

&lt;p&gt;If you carefully followed all the steps, you should be now able to access the SerpBear instance on the (sub)domain of your choosing. Log in using the chosen credentials from the previous step. You should see a red prompt at the top to configure your &lt;em&gt;Scrapper/Proxy&lt;/em&gt;. Click on it to open settings, choose &lt;em&gt;SerpApi.com&lt;/em&gt; as the &lt;em&gt;Scraping Method&lt;/em&gt; and insert your SerpApi API token under &lt;em&gt;Scraper API Key Or Token&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixend0ftf2mskym40yxi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixend0ftf2mskym40yxi.png" alt="SerpBear settings" width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Update Settings&lt;/strong&gt; to close the right sidebar and you'll be ready to add your first keywords to track. Start by adding a domain name. After entering your domain name you should end up on the &lt;em&gt;Tracking&lt;/em&gt; tab for the domain.&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Add Keyword&lt;/strong&gt; and start adding keywords and phrases you care about. They should appear in a nice table with their last position, best position, history graph, volume, and URL. Here's an example of tracking "serp api" for serpapi.com in the Czech Republic:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frm9j1lmysprto8m5z0pi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frm9j1lmysprto8m5z0pi.png" alt="SerpBear keywords" width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's it! You can now add as many domains and keywords as you want to. Remember that SEO today is not just about tracking organic results in Google, so have a look at &lt;a href="https://serpapi.com/blog/rank-tracking-in-the-age-of-ai-overviews-whats-changed/" rel="noopener noreferrer"&gt;AI overviews&lt;/a&gt; as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;As next steps you can consider adding your Google Search Console data to SerpBear, handle external backups in Coolify, or exploring more of &lt;a href="https://serpapi.com" rel="noopener noreferrer"&gt;SerpApi&lt;/a&gt;. The Free tier comes with &lt;strong&gt;250 free searches&lt;/strong&gt; per month.&lt;/p&gt;

</description>
      <category>selfhosting</category>
    </item>
    <item>
      <title>How to start self-hosting with Coolify 4 on a VPS</title>
      <dc:creator>Josef Strzibny</dc:creator>
      <pubDate>Wed, 01 Apr 2026 11:57:51 +0000</pubDate>
      <link>https://dev.to/serpapi/how-to-start-self-hosting-with-coolify-4-on-a-vps-44ob</link>
      <guid>https://dev.to/serpapi/how-to-start-self-hosting-with-coolify-4-on-a-vps-44ob</guid>
      <description>&lt;p&gt;Coolify is an open source Platform as a Service (PaaS) that can help you self-host a lot of different software from content management tools like Ghost to SEO tracking software like SerpBear. The only thing you'll need is a virtual private server (VPS) from a hosting provider of your choice and a little bit of set up which is exactly what we'll go through in this post.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡&lt;/p&gt;

&lt;p&gt;Coolify v4 is still beta software as of the time of writing of this post. If you need a little bit more stability, wait for the final release.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is Coolify?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvv4bflbq7tzhjagp3lv0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvv4bflbq7tzhjagp3lv0.png" alt="Coolify logo" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/coollabsio/coolify" rel="noopener noreferrer"&gt;Coolify&lt;/a&gt; is a self-hostable alternative to Heroku, Vercel, or Netlify. It's an open source PaaS that allows developers to deploy their applications as well as manage 3rd-party services and databases.&lt;/p&gt;

&lt;p&gt;Some of the biggest advantages include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosted control:&lt;/strong&gt;  You own your data on your own servers which saves money and avoids vendor lock-in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hosting versatility:&lt;/strong&gt;  Hosts web applications, static websites, databases (PostgreSQL, MySQL, MongoDB, etc.), and services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated DevOps:&lt;/strong&gt;  Automatically installs dependencies, sets up databases, and handles deployments from GitHub, GitLab, or Bitbucket.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web console:&lt;/strong&gt;  Offers a web-based dashboard for managing multiple servers, viewing logs, and monitoring resource usage like CPU and RAM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in tools:&lt;/strong&gt;  Features automatic S3-compatible backups, auto provisioning of SSL certificates, webhooks, or preview deployments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can run Coolify in various ways. You can use a single server for everything you host or do a separate deployment for the services you'll run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Applications, databases and services
&lt;/h3&gt;

&lt;p&gt;Coolify supports deploying custom applications and 3rd-party services. It generally distinguish between 3 different types of resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Applications&lt;/strong&gt; come with &lt;strong&gt;a git source&lt;/strong&gt; or are built using Docker from &lt;strong&gt;Dockerfile&lt;/strong&gt;. You can deploy anything from &lt;a href="https://serpapi.com/integrations/php" rel="noopener noreferrer"&gt;PHP&lt;/a&gt; to &lt;a href="https://serpapi.com/integrations/java" rel="noopener noreferrer"&gt;Java&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Databases&lt;/strong&gt; are preconfigured Docker images for running databases, like MySQL or PostgreSQL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Services&lt;/strong&gt; are deployments based on  &lt;strong&gt;Docker Compose&lt;/strong&gt; files that are stored directly on the server. You deploy well known software like Ghost.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can mix and match any of these on a single Coolify instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the virtual server
&lt;/h2&gt;

&lt;p&gt;There are two variants to self-hosting. One with physical servers that are usually dedicated to you and one with virtual servers where you share the underlying physical servers with others.&lt;/p&gt;

&lt;p&gt;We'll set up a simple virtual server on Hetzner which is a provider praised for its affordable costs. You are free to use any other provider you like or already have. Some other popular providers include Digital Ocean, Vultr, or OVHcloud.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡&lt;/p&gt;

&lt;p&gt;Coolify currently offers $20 credit for deploying to Hetzner by following the &lt;a href="https://coolify.io/hetzner" rel="noopener noreferrer"&gt;https://coolify.io/hetzner&lt;/a&gt; link.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To create a virtual private server (VPS), you'll need an SSH key pair which you'll authenticate with in the future. You can optionally set a password for the private key as well. To generate a new one, run &lt;code&gt;ssh-keygen&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh-keygen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The command will interactively ask you about your key details. If you name it &lt;em&gt;coolify&lt;/em&gt; you should end up with two files inside the &lt;code&gt;~/.ssh&lt;/code&gt; directory, one for private key and one for public key (&lt;code&gt;coolify.pub&lt;/code&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡&lt;/p&gt;

&lt;p&gt;Protect your SSH private key! You always provide others with your public key, not the private key. The private key should stay with you on your computer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you have your key pair, it's fairly straightforward to spin up a new server with the provider of your choice.&lt;/p&gt;

&lt;p&gt;On Hetzner, create a new project and on the project overview click &lt;strong&gt;Add Server&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffgr3ye1zo0zmrcobmmg6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffgr3ye1zo0zmrcobmmg6.png" alt="Creating a server on Hetzner" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select a location close to you, Ubuntu 24.04 or your favorite operating system (Debian, SUSE, and Fedora based systems are supported), the size you want, and optionally enable full virtual machine backups. Under &lt;em&gt;SSH Keys&lt;/em&gt; upload your &lt;strong&gt;public SSH key&lt;/strong&gt; which should disable password-based access on most providers and let you use your private key instead.&lt;/p&gt;

&lt;p&gt;As for the size of the box, Coolify recommends at least 2 vCPUs, 2 GB of RAM, and 30 GB of storage space. If you are going to self-host projects on the same instance, you generally need to increase the box size accordingly. For only running one or two extra applications, consider increasing RAM.&lt;/p&gt;

&lt;p&gt;This is all that's needed for things to work, but we can also provide a custom cloud-init script under &lt;em&gt;Cloud config&lt;/em&gt;. For example, we can set up automatic system updates and install fail2ban for extra protection of our SSH port:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Do a system update
apt update;
DEBIAN_FRONTEND=noninteractive apt upgrade -y

# Install essential packages
apt install -y curl unattended-upgrades fail2ban

# Set up unattented updates
echo -e "APT::Periodic::Update-Package-Lists \"1\";\nAPT::Periodic::Unattended-Upgrade \"1\";\n" &amp;gt; /etc/apt/apt.conf.d/20auto-upgrades
/etc/init.d/unattended-upgrades restart

# Install fail2ban
systemctl start fail2ban.service
systemctl enable fail2ban.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can optionally install Docker at this step from the system package manager but &lt;strong&gt;do not&lt;/strong&gt; install Docker from Snap as that's not supported by Coolify.&lt;/p&gt;

&lt;p&gt;Finally, give the server a name (you can call it &lt;em&gt;coolify&lt;/em&gt;, but do not use a domain name) and click &lt;strong&gt;Create &amp;amp; Buy now&lt;/strong&gt;. Provisioning the server will take some minutes and once done you should be able to find the public server IPv4 address next to its name on the server page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwrli5gt5me89w7jtem5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwrli5gt5me89w7jtem5.png" alt="Server details on Hetzner" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should now be able to log in from your terminal as:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh-add ~/.ssh/path-to-your-key
ssh root@[IP_ADDRESS]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There is quite a bit more to running and securing servers. You should ideally choose a different user than &lt;em&gt;root&lt;/em&gt; and/or disable public SSH access altogether in the cloud's firewall. If you want to do that, have a look at WireGuard or Tailscale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring DNS
&lt;/h2&gt;

&lt;p&gt;Now that you have a public IP address, you can create DNS records to get nice URLs for accessing Coolify, SerpBear, and whatever else you decide to self host.&lt;/p&gt;

&lt;p&gt;Head over to your domain registrar console and set the DNS A records for domains or subdomains you want to use for Coolify and the applications you want to host:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# For accesing Coolify web console (admin area)
coolify.example.com -&amp;gt; 178.104.25.112

# Example application
serpbear.example.com -&amp;gt; 178.104.25.112
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Choose "A" type records to directly connect a domain name or subdomain to the IP address (replace the values, the above is just an example). You can use Porkbun or GoDaddy to register your first domain name if you don't have one yet.&lt;/p&gt;

&lt;p&gt;Since we'll run everything on a single host, the IP address remains the same for all instances.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Coolify
&lt;/h2&gt;

&lt;p&gt;Now that we have our Linux box up and running, we can SSH into it and run the official installer script:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -fsSL https://cdn.coollabs.io/coolify/install.sh | sudo bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can change some installation details with environment variables, so go and &lt;a href="https://coolify.io/docs/get-started/installation#advanced-customizing-installation-with-environment-variables" rel="noopener noreferrer"&gt;review this list&lt;/a&gt; before running the script.&lt;/p&gt;

&lt;p&gt;For example, you might want to choose the admin username, email, and password:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;env ROOT_USERNAME=admin \
ROOT_USER_EMAIL=admin@example.com \
ROOT_USER_PASSWORD=SecurePassword123 \
bash -c 'curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once run, you'll see a &lt;em&gt;Congratulations!&lt;/em&gt; screen with the list of the IP addresses, version as well as a log file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;____ _ _ _ _ _
  / ___|___ _ ____ _ _ ____ _| |_ _ _| | ___| |_(_)___ _ _____ | |
 | | / _ \| '_ \ / _` | ' __/ _` |__ | | | | |/ _` | __| |/ _ \| '_ \/__ | |
 | |__| (_) | | | | (_| | | | (_| | |_| |_| | | (_| | |_| | (_) | | | \__ \_|
  \ ____\___ /|_| |_|\ __, |_| \__ ,_|\ __|\__ ,_|_|\ __,_|\__ |_|\ ___/|_| |_|___ (_)
                   |___/


Your instance is ready to use!

You can access Coolify through your Public IPV4: http://178.104.25.112:8000
You can access Coolify through your Public IPv6: http://[2a01:4f8:1c19:f81a::1]:8000

If your Public IP is not accessible, you can use the following Private IPs:

http://10.0.0.1:8000
http://10.0.1.1:8000
http://2a01:4f8:1c19:f81a::1:8000
http://fdb0:c330:3639::1:8000

WARNING: It is highly recommended to backup your Environment variables file (/data/coolify/source/.env) to a safe location, outside of this server (e.g. into a Password Manager).


============================================================
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;[2026-03-19 11:02:44] Installation Complete&lt;br&gt;
    ============================================================&lt;br&gt;
[2026-03-19 11:02:44] Coolify installation completed successfully&lt;br&gt;
[2026-03-19 11:02:44] Version: 4.0.0-beta.468&lt;br&gt;
[2026-03-19 11:02:44] Log file: /data/coolify/source/installation-20260319-110120.log&lt;/p&gt;

&lt;p&gt;After installation, you should find your self-hosted Coolify instance at &lt;a href="http://203.0.113.1:8000" rel="noopener noreferrer"&gt;&lt;code&gt;http://[IP_ADDRESS]:8000&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosc405o9brtdo9030uvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosc405o9brtdo9030uvq.png" alt="Coolify welcome page" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see a &lt;em&gt;Welcome to Coolify&lt;/em&gt; screen. Click &lt;strong&gt;Let's go!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6veytuocsa5v3x7zabat.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6veytuocsa5v3x7zabat.png" alt="Coolify sign up" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create your root account and on the next screen choose &lt;em&gt;This Machine&lt;/em&gt; as your server type (we'll run everything on a single instance):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ctgo1o5skz5ogwxie3m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ctgo1o5skz5ogwxie3m.png" alt="Coolify server type selection" width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the initial wizard, let's go to &lt;em&gt;Settings&lt;/em&gt; (from the left menu) and input the instance URL with our (sub)domain we prepared for Coolify under &lt;em&gt;General&lt;/em&gt; (make sure to include full URL including the leading &lt;code&gt;https://&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2un11h72yuweql3dscb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2un11h72yuweql3dscb.png" alt="Coolify localhost instance settings" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Optionally you can also explore the &lt;em&gt;Backup&lt;/em&gt; and &lt;em&gt;Transactional Email&lt;/em&gt; tabs for setting up Coolify backups and transactional emails (for things like forgotten password).&lt;/p&gt;

&lt;p&gt;Then head over to &lt;em&gt;Servers&lt;/em&gt; (from the left menu) where you should see our &lt;em&gt;localhost&lt;/em&gt; instance (running Coolify). Here you'll find settings for the Coolify components. Open it and go to the &lt;em&gt;Proxy&lt;/em&gt; tab:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhgq3495fzrngc5j129jc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhgq3495fzrngc5j129jc.png" alt="Coolify proxy" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Checking that the proxy is running is important as it will route the traffic to the applications you'll self host. Even if Coolify is running and you are logged in inside the console, the &lt;em&gt;coolify-proxy&lt;/em&gt; might not be.&lt;/p&gt;

&lt;p&gt;In case the proxy is not running, open the logs and see what's wrong. In my case, the proxy wasn't running and I found the following inside the logs:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Creating required Docker Compose file.
Pulling docker image.
 Image traefik:v3.6 Pulling 
 Image traefik:v3.6 Pulled 
Ensuring network coolify exists...
Ensuring network havzqyfu212ybs9n5lg48gzy exists...
Starting coolify-proxy.
ParseAddr("fdb0:c330:3639::1/64"): unexpected character, want colon (at "/64")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There seemed to be an issue with parsing an IPv6 address. To resolve it I decided to turn off IPv6 support on the system. I opened an SSH connection to the server again to edit Docker's daemon.json file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vi /etc/docker/daemon.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I added an entry with &lt;code&gt;"ipv6": false&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "default-address-pools": [
    {"base":"10.0.0.0/8","size":24}
  ],
  "ipv6": false
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then I restarted Docker:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After that I could restart the proxy and see coolify-proxy container running on the system.&lt;/p&gt;

&lt;p&gt;And that was it! If you can log in and see that the proxy is running, you are ready to start adding individual applications and services. You can still also use a hosted version of Coolify if you never set up a server before and all of this looks daunting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying resources
&lt;/h2&gt;

&lt;p&gt;Resources in Coolify needs a project, so open &lt;em&gt;Projects&lt;/em&gt; from the left side menu, and click &lt;strong&gt;+ Add&lt;/strong&gt; next to Projects. Then click &lt;strong&gt;+ New&lt;/strong&gt; next to the &lt;em&gt;Resources&lt;/em&gt; headline. You should arrive on a &lt;em&gt;New Resource&lt;/em&gt; page which lets you choose what you want to run. You can deploy directly from a git repository, Dockerfile or custom Docker Compose.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhlk8fn21xy2pa5hi5xll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhlk8fn21xy2pa5hi5xll.png" alt="Coolify applications" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  One-click services
&lt;/h3&gt;

&lt;p&gt;One-click services are pre-configured Docker Compose templates provided directly by Coolify, skipping the complexity of manual setup and configuration. They are the easiest to start with.&lt;/p&gt;

&lt;p&gt;Scroll a bit down and you should see them:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ffb26wsxrw9r0a9pgvv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ffb26wsxrw9r0a9pgvv.png" alt="Coolify one-click services" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Coolify also maintains &lt;a href="https://coolify.io/docs/services/all" rel="noopener noreferrer"&gt;a directory&lt;/a&gt; for these services on the web. Some of services you can add are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Internal tools:&lt;/strong&gt;  Appsmith, Budibase, NocoDB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chat &amp;amp; messaging:&lt;/strong&gt;  Matrix, Mattermost, Rocket.Chat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Development &amp;amp; CI/CD:&lt;/strong&gt;  VS Code Server, Gitea, Jenkins.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring &amp;amp; analytics:&lt;/strong&gt;  Bugsink, CloudBeaver.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CMS:&lt;/strong&gt;  WordPress, Ghost.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are all pretested, optimized, and coming with sensible defaults.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom services
&lt;/h3&gt;

&lt;p&gt;Custom services in Coolify are those that you deploy with your own &lt;strong&gt;Docker Compose&lt;/strong&gt; file. They require a little bit more work, but allow you to run almost anything. Have a look at &lt;a href="https://serpapi.com/blog/self-host-serpbear-coolify/" rel="noopener noreferrer"&gt;how to deploy SerpBear&lt;/a&gt;, a SEO tool for keyword tracking as an example of a custom service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;If you are new to self-hosting make sure to learn a little bit more about SSH, DNS, Linux, Docker, and related topics. You should also have a look at the Coolify &lt;a href="https://coolify.io/docs/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for even more information and tips.&lt;/p&gt;

</description>
      <category>selfhosting</category>
    </item>
    <item>
      <title>I wrote a handbook for Kamal</title>
      <dc:creator>Josef Strzibny</dc:creator>
      <pubDate>Fri, 05 Apr 2024 08:49:28 +0000</pubDate>
      <link>https://dev.to/strzibny/i-wrote-a-handbook-for-kamal-1d76</link>
      <guid>https://dev.to/strzibny/i-wrote-a-handbook-for-kamal-1d76</guid>
      <description>&lt;p&gt;Kamal is an imperative deployment tool. It's basically a successor to Capistrano, but for a container era. It's a simple wrapper around Docker and that's the whole beauty of it. 37signals created Kamal to self-host Basecamp and Hey as part of their pull out of the cloud (running managed K8s).&lt;/p&gt;

&lt;p&gt;I am always for simplicity when it comes to deployment and the truth is that lots of projects out there don't need the fully-featured Kubernetes to run. When Kamal was released I got intrigued and slowly adopted the tool. Nowadays I deploy all new projects with it.&lt;/p&gt;

&lt;p&gt;Since the documentation is a little sparse at the moment and some people trying Kamal abandoned the effort when they faced their first issues, I decided to do something about it and wrote 'the missing manual' to Kamal called &lt;a href="https://kamalmanual.com/handbook/"&gt;Kamal Handbook&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The book goes through all the important aspects of deploying with Kamal, describes the design choices and explains what's happening under the hood with illustrations. It's by design a small book you can read in a weekend. Hope you'll like it.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>docker</category>
      <category>kamal</category>
    </item>
    <item>
      <title>I just released InvoicePrinter 2.0</title>
      <dc:creator>Josef Strzibny</dc:creator>
      <pubDate>Wed, 02 Oct 2019 11:50:08 +0000</pubDate>
      <link>https://dev.to/strzibny/i-just-released-invoiceprinter-2-0-5da0</link>
      <guid>https://dev.to/strzibny/i-just-released-invoiceprinter-2-0-5da0</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/strzibny/invoice_printer"&gt;InvoicePrinter&lt;/a&gt; is a Ruby library, server, and command-line client to make beautiful PDF invoices without browsers in no time. It's pure Ruby, but can be also used outside the Ruby world as a Docker container with a simple JSON API.&lt;/p&gt;

&lt;p&gt;New features in 2.0:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New modern look &amp;amp; feel&lt;/li&gt;
&lt;li&gt;More flexible buyer/seller boxes&lt;/li&gt;
&lt;li&gt;Server is decoupled to a separate gem &lt;code&gt;invoice_printer_server&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;New bundled fonts in a separate gem &lt;code&gt;invoice_printer_fonts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Official Docker image&lt;/li&gt;
&lt;li&gt;Prawn 2.2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the project &lt;a href="https://github.com/strzibny/invoice_printer"&gt;GitHub page&lt;/a&gt;, in the &lt;code&gt;examples/&lt;/code&gt; directory you can find a lot of code examples and how they look as PDFs. Follow &lt;code&gt;docs/&lt;/code&gt; to learn more about using it as a library, server or a command-line client.&lt;/p&gt;

&lt;p&gt;Here is one example (&lt;a href="https://github.com/strzibny/invoice_printer/raw/master/examples/promo_a4.pdf"&gt;download the final PDF&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YoDO3fMc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/5ro56bflouziq6puy2kx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YoDO3fMc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/5ro56bflouziq6puy2kx.jpg" alt="Alt Text" width="800" height="1132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And Ruby code to generate it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env ruby&lt;/span&gt;
&lt;span class="c1"&gt;# This is an example of a international invoice with Czech labels and English translation.&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'invoice_printer'&lt;/span&gt;

&lt;span class="n"&gt;labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s1"&gt;'Faktura'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;provider: &lt;/span&gt;&lt;span class="s1"&gt;'Prodejce'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;purchaser: &lt;/span&gt;&lt;span class="s1"&gt;'Kupující'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;tax_id: &lt;/span&gt;&lt;span class="s1"&gt;'IČ'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;tax_id2: &lt;/span&gt;&lt;span class="s1"&gt;'DIČ'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;payment: &lt;/span&gt;&lt;span class="s1"&gt;'Forma úhrady'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;payment_by_transfer: &lt;/span&gt;&lt;span class="s1"&gt;'Platba na následující účet:'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;account_number: &lt;/span&gt;&lt;span class="s1"&gt;'Číslo účtu'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;issue_date: &lt;/span&gt;&lt;span class="s1"&gt;'Datum vydání'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;due_date: &lt;/span&gt;&lt;span class="s1"&gt;'Datum splatnosti'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;item: &lt;/span&gt;&lt;span class="s1"&gt;'Položka'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;quantity: &lt;/span&gt;&lt;span class="s1"&gt;'Počet'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;unit: &lt;/span&gt;&lt;span class="s1"&gt;'MJ'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;price_per_item: &lt;/span&gt;&lt;span class="s1"&gt;'Cena za položku'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;amount: &lt;/span&gt;&lt;span class="s1"&gt;'Celkem bez daně'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;subtotal: &lt;/span&gt;&lt;span class="s1"&gt;'Cena bez daně'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;tax: &lt;/span&gt;&lt;span class="s1"&gt;'DPH 21 %'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;total: &lt;/span&gt;&lt;span class="s1"&gt;'Celkem'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Default English labels as sublabels&lt;/span&gt;
&lt;span class="n"&gt;sublabels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;InvoicePrinter&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;PDFDocument&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DEFAULT_LABELS&lt;/span&gt;
&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge!&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="ss"&gt;sublabels: &lt;/span&gt;&lt;span class="n"&gt;sublabels&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="n"&gt;first_item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;InvoicePrinter&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s1"&gt;'Konzultace'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;quantity: &lt;/span&gt;&lt;span class="s1"&gt;'2'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;unit: &lt;/span&gt;&lt;span class="s1"&gt;'hod'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="s1"&gt;'Kč 500'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;amount: &lt;/span&gt;&lt;span class="s1"&gt;'Kč 1.000'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;second_item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;InvoicePrinter&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s1"&gt;'Programování'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;quantity: &lt;/span&gt;&lt;span class="s1"&gt;'10'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;unit: &lt;/span&gt;&lt;span class="s1"&gt;'hod'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="s1"&gt;'Kč 900'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;amount: &lt;/span&gt;&lt;span class="s1"&gt;'Kč 9.000'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;provider_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;ADDRESS&lt;/span&gt;&lt;span class="sh"&gt;
Rolnická 1
747 05  Opava
Kateřinky
&lt;/span&gt;&lt;span class="no"&gt;ADDRESS&lt;/span&gt;

&lt;span class="n"&gt;purchaser_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;ADDRESS&lt;/span&gt;&lt;span class="sh"&gt;
Ostravská 1
747 70  Opava
&lt;/span&gt;&lt;span class="no"&gt;ADDRESS&lt;/span&gt;

&lt;span class="n"&gt;invoice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;InvoicePrinter&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;number: &lt;/span&gt;&lt;span class="s1"&gt;'č. 198900000001'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;provider_name: &lt;/span&gt;&lt;span class="s1"&gt;'Petr Nový'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;provider_lines:  &lt;/span&gt;&lt;span class="n"&gt;provider_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;provider_tax_id: &lt;/span&gt;&lt;span class="s1"&gt;'56565656'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;purchaser_name: &lt;/span&gt;&lt;span class="s1"&gt;'Adam Černý'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;purchaser_lines: &lt;/span&gt;&lt;span class="n"&gt;purchaser_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;issue_date: &lt;/span&gt;&lt;span class="s1"&gt;'05/03/2016'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;due_date: &lt;/span&gt;&lt;span class="s1"&gt;'19/03/2016'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;subtotal: &lt;/span&gt;&lt;span class="s1"&gt;'Kč 10.000'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;tax: &lt;/span&gt;&lt;span class="s1"&gt;'Kč 2.100'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;total: &lt;/span&gt;&lt;span class="s1"&gt;'Kč 12.100,-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;bank_account_number: &lt;/span&gt;&lt;span class="s1"&gt;'156546546465'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;account_iban: &lt;/span&gt;&lt;span class="s1"&gt;'IBAN464545645'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;account_swift: &lt;/span&gt;&lt;span class="s1"&gt;'SWIFT5456'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;items: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;first_item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;second_item&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="ss"&gt;note: &lt;/span&gt;&lt;span class="s1"&gt;'Osoba je zapsána v živnostenském rejstříku.'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="no"&gt;InvoicePrinter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;document: &lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;labels: &lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;font: &lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'../../assets/fonts/overpass/Overpass-Regular.ttf'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="ss"&gt;logo: &lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'../logo.png'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="ss"&gt;file_name: &lt;/span&gt;&lt;span class="s1"&gt;'promo.pdf'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;page_size: :a4&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before the final release I wrote a little background post on my &lt;a href="http://nts.strzibny.name/invoiceprinter-2-0/"&gt;blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Try it out and let me know what you think!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>docker</category>
      <category>pdf</category>
      <category>invoicing</category>
    </item>
    <item>
      <title>Django 2.2 polls app tutorial source code commit by commit</title>
      <dc:creator>Josef Strzibny</dc:creator>
      <pubDate>Tue, 09 Apr 2019 22:47:01 +0000</pubDate>
      <link>https://dev.to/strzibny/django-2-2-polls-app-tutorial-source-code-commit-by-commit-3glk</link>
      <guid>https://dev.to/strzibny/django-2-2-polls-app-tutorial-source-code-commit-by-commit-3glk</guid>
      <description>&lt;p&gt;TL;DR&lt;/p&gt;

&lt;p&gt;I went through the famous Django "polls" app tutorial, and made it into a git repository which you can follow commit by commit:&lt;/p&gt;

&lt;p&gt;GitHub link: &lt;a href="https://github.com/deployment-from-scratch/django-2.2-polls"&gt;deployment-from-scratch/django-2.2-polls&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tutorial link: &lt;a href="https://docs.djangoproject.com/en/2.2/intro/tutorial01/"&gt;Writing your first Django app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's for Django 2.2.&lt;/p&gt;

&lt;p&gt;Full Story:&lt;/p&gt;

&lt;p&gt;Since the beginning of time (me wanting to leave PHP development) I was intrigued by Ruby on Rails and Django frameworks. I liked both for different reasons, but ended up doing mainly Rails because of Ruby the language (and living with a syndrome that I might made a mistake ever since).&lt;/p&gt;

&lt;p&gt;Fast forward to 2019, and I am writing a book on &lt;a href="http://deploymentfromscratch.com"&gt;deploying web application&lt;/a&gt; where I am trying to teach deployment of both Ruby &lt;em&gt;and&lt;/em&gt; Python apps. There are pretty similar in that regards actually, but I needed some Python examples.&lt;/p&gt;

&lt;p&gt;For this reason, I went to the Django site after many years (it's a lie, I keep watching Django space haha) and did the famous introductory tutorial of building "polls" app. I did it "commit by commit" so people can follow it easily while going through the tutorial.&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
