[HN Gopher] Deploy from local to production (self-hosted)
       ___________________________________________________________________
        
       Deploy from local to production (self-hosted)
        
       Author : bypirob
       Score  : 120 points
       Date   : 2025-03-08 18:54 UTC (1 days ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | barrettshepherd wrote:
       | What's the advantage of this over Kamal? (https://kamal-
       | deploy.org/)
        
         | ngrilly wrote:
         | I like that it's a single file executable. But Kamal offers
         | much more, for eample zero-downtime deployment.
        
         | oulipo wrote:
         | Also Dokploy, Dokku, Coolify and similar
        
           | ajayvk wrote:
           | Another option you could consider is a tool I have been
           | building for deploying webapps across a team.
           | https://github.com/claceio/clace has the usual deployment
           | related functionality like gitops, TLS certs.
           | 
           | It has some unique features like supporting OAuth
           | authentication for the apps, staging env for each app (code
           | and config changes are staged before deployment), supporting
           | declarative update, supporting hypermedia based apps natively
           | etc.
        
             | notpushkin wrote:
             | This is so cool! The scope is a bit broad (it's a build
             | tool, DevOps tool _and_ a hypermedia app framework?) -
             | maybe you could split this into multiple projects and start
             | a whole ecosystem?
             | 
             | I'm also working on a deployment tool, though not nearly as
             | ambitious - it's just a Docker dashboard based around
             | Compose files: https://lunni.dev/ (though it does
             | everything Traefik does, and GitOps are also definitely on
             | the roadmap)
        
               | ajayvk wrote:
               | Thanks. Clace is built for teams to be be able to deploy
               | internal tools (Streamlit/Gradio etc). That use case
               | requires some extra features (OAuth/Auditing/Declarative
               | config etc). Kubernetes with ArgoCD plus IDP seems to
               | have become the default solution, which is overkill for
               | such use cases.
               | 
               | The Hypermedia based app support was added to be able to
               | build a management dashboard for Clace itself, without
               | going down the SPA route. It made sense to expose that
               | for end uses to be able to build their own apps.
        
       | indigodaddy wrote:
       | This seems cool and all but it's fairly trivial to docker compose
       | whatever stuffs/apps you want and install caddy as the reverse
       | proxy on the host (I normally don't do caddy in a container but
       | it might be better to)
       | 
       | You have to setup docker compose files with airo it looks like in
       | any case, so this just simplifies the caddy part? But caddy is so
       | simple to begin with I'm not sure the point..
        
         | ratorx wrote:
         | Does it even configure caddy? I can't see how the caddy config
         | could be generated from the env.yaml (unless it relies on the
         | directory name etc for the path).
         | 
         | Seems like something that could have been solved with just
         | docker compose (by setting a remote DOCKER_HOST). If you need
         | "automatic" proxying, then traefik can do it off container
         | labels.
        
           | timdorr wrote:
           | Nope, it just copies over a hand-made Caddyfile and restarts
           | a docker container that you need to already be running: https
           | ://github.com/bypirob/airo/blob/1a827a76f2254e5ca4f4ba4...
           | 
           | This looks extremely barebones and makes a large number of
           | assumptions in its current state. This is better as a Show HN
           | after some more dev work has been completed.
        
             | notpushkin wrote:
             | Agreed - it's a bit too early to publicize this. Lots of
             | great alternatives discussed here though!
             | 
             | Maybe I should try to Show HN my Docker dashboard,
             | https://lunni.dev/ :thinking:
        
             | globular-toast wrote:
             | Surprised it doesn't use caddy-docker-proxy to
             | automatically route traffic to your compose set up. You
             | could just do that in dev and have a very simple compose
             | override for prod that changes the domain names etc.
        
         | delduca wrote:
         | Docker compose + Cloudflare Tunnels is my current setup, no
         | need to deal with SSL, have a public IP address, and if you
         | make use of Tailscale, you do need any open ports, witch is
         | extremely secure and robust.
        
           | Hikikomori wrote:
           | Same, I use dockge to manage them. Then I use cloudflare zero
           | trust with email login to access them instead of using a vpn,
           | don't have to install vpn on multiple devices and my partners
           | devices.
        
       | zelifcam wrote:
       | Imagine if people just used the tools themselves instead of
       | creating yet another layer in hopes of simplifying something that
       | can already be done with a few lines on a bash script.
        
         | cdfuller wrote:
         | Agreed. This project isn't that upfront this is a wrapper
         | around 4 commands. Docker build, docker push, docker pull and
         | compose up.
        
           | morcus wrote:
           | For small projects you can also add something like Watchtower
           | to your compose file and then you need only build and push
           | the image.
           | 
           | And I assume you want to be building once to test your
           | changes anyways, so you really only need to push.
        
           | MyOutfitIsVague wrote:
           | Whew, you're not joking. This whole thing is 156 lines of Go.
           | I'd probably have just used a shell script for this kind of
           | thing.
        
             | 0xbadcafebee wrote:
             | I think we can all agree that any Go program that just
             | executes some other program, is way better than a shell
             | script!
             | 
             | I mean, what if you needed to change the way it worked?
             | With bash you'd have to open a text editor, change a line,
             | and save the file! And on top of that you need to
             | understand shell scripting!
             | 
             | With Go, you can set up your development environment, edit
             | the source code, run the compiler, download the external
             | dependencies, generate a new binary, and copy it to your
             | server. And all this requires is learning the Go language
             | and its development model. This is clearly more advanced,
             | and thus better.
        
               | indigodaddy wrote:
               | Haha, nice
        
             | xnyan wrote:
             | I know ansible is not sexy or resource efficient, but it
             | would be a handful of lines in a single task.yml and it
             | would work reliably out of the box. Previously the part
             | that was too much effort for me to be reliable was often
             | bootstrapping the python environment on the host, but uv
             | has been a game changer (at least it has been from my team)
             | in terms of being able to efficiently and reliably ensure
             | the exact python environment we want.
        
               | Terretta wrote:
               | > > _" 156 lines of go"_
               | 
               | > _" Ansible ... would be a handful of lines"_
               | 
               | How many lines are a handful? Ansible is a few hundred
               | thousand.
               | 
               | If you're enjoying `uv`, consider `mise` for small
               | helpers like the above.
               | 
               | Plays well with `uv`, handles this sort of thing with
               | tasks:
               | 
               | https://mise.jdx.dev/tasks/
        
           | ianburrell wrote:
           | This is perfect use for Make. Have command for build, push,
           | and deploy. Then have one to do them all together. The
           | advantage is can do individual commands, and put one for
           | building and testing locally.
           | 
           | Long scripts suck in Makefile, but can call external scripts
           | for anything big.
        
         | xandrius wrote:
         | Exactly, for over 4 years I've been using my trusty 10 lines of
         | bash (most of them is confirmation) to deploy in seconds and
         | with 0 downtime. I should probably opensource it, lol
        
           | Wilduck wrote:
           | I know you're joking a little, but I personally would love to
           | see them! I'm very interested in how people manage simple
           | deploys.
        
             | tbocek wrote:
             | Here is mine, I have a docker compose file locally, and
             | this deploy.sh script deploy to my remote machine. That
             | also means that my remote machine is building the image.
             | And I have not found a good solution for secrets/env files
             | yet:                 #!/usr/bin/env bash
             | export DOCKER_HOST="ssh://username@host:port"       docker
             | compose up -d --build
        
               | xandrius wrote:
               | For secrets, just literally have an ssh command which
               | reads the local .env file and uses them to start the
               | server with them as arguments/env vars.
        
           | leosanchez wrote:
           | Do you use symlinks to achieve 0 downtime ? Assuming it is a
           | systemd service ?.
           | 
           | If possible could you share gist of that script ?
        
         | polishdude20 wrote:
         | My method is I push my code to master and then ssh to my
         | server, git pull and restart the server
        
           | Etheryte wrote:
           | while true; do git pull && sudo reboot; done
        
       | mediumsmart wrote:
       | I use rsync in a script. One line builds and the second line
       | deploys - but that pushes to a server someone else has standing
       | on the ground with a disk in it that hosts the site I myself made
       | on a local machine. If I self-hoist the production server into my
       | flat, couldn't I just copy the folder without the internet like
       | from local to local?
        
         | rad_gruchalski wrote:
         | No need to even copy a folder, simply link it.
        
       | scottydelta wrote:
       | I have been using coolify on a bare metal server and it has been
       | such a great experience.
       | 
       | The ability to spin up services is crazy good and easy. I was
       | able to evaluate n8n, windmill.dev and prefect in 3 hours because
       | I was able to quickly setup these clusters and test them. And
       | final thing was to compile my code as docker container and spin
       | it up on coolify within mins with custom domain and ssl.
       | 
       | How is it different and eaiser than coolify kinda setup?
        
         | jilles wrote:
         | I did the same. Really enjoyed Coolify but at some point there
         | was too much magic.
         | 
         | I'm now using Dokku and can't imagine using something else.
        
           | sameklund wrote:
           | Considering both of these right now. Why was Dokku so much
           | better for you?
        
             | notpushkin wrote:
             | I'm working on Lunni - similar to Coolify, but centered
             | around compose files (hopefully that's less magic!):
             | https://lunni.dev/
             | 
             | Would love to hear your thoughts if you give it a try!
        
               | sameklund wrote:
               | Looks like this is a web UI for docker swarm? Does it
               | have additional PaaS-like features? I think I would
               | probably just use Portainer if I wanted a GUI. Unless I
               | am missing something?
        
               | notpushkin wrote:
               | Lunni _is_ similar to Portainer. (And it uses Portainer
               | as the backend, actually!)
               | 
               | Before I started Lunni, I was using Portainer myself, but
               | it got too painful. Here are some paper cuts I'm trying
               | to solve with Lunni:
               | 
               | - I only manage one cluster (of one server), but I still
               | had to select endpoint every time. In Lunni, the first
               | thing you see when you log in is the status of your
               | stacks/projects
               | 
               | - I use Traefik with routing config living in service
               | labels. It's a huge snippet, impossible to remember,
               | which I had to copy from project to project. In Lunni
               | it's autocompleted for you: https://lunni.dev/docs/deploy
               | /#:~:text=This%20is%20quite%20l...
               | 
               | - When you look at the service logs in Portainer, they
               | refresh once in a while and throw away your scroll
               | position, which is super frustrating. In Lunni, it works
               | as you'd expect. As a bonus, you can copy a link to a log
               | line (e.g. if you want to share it with somebody or just
               | bookmark it)
               | 
               | - If you need to create a Docker config or secret for a
               | stack in Portainer, you have to go to another dashboard
               | section, make a config yourself, then copy the name to
               | your stack. In Lunni, you can do that right on the New
               | project page: https://lunni.dev/docs/configs-secrets/
               | 
               | - ...and a lot of other things like error messages that
               | don't disappear in 5 seconds, before you've had a chance
               | to read them
               | 
               | Basically, I'm trying to make a Portainer that is a
               | pleasure to use. Maybe it's not as close to Coolify as I
               | thought, but I'm trying to maintain a more PaaSy _feel_
               | than Portainer. Some things you'd expect from a PaaS,
               | like a built in CI and automated DB /volume backups, are
               | also on the roadmap!
        
         | kilroy123 wrote:
         | Same here but I've certainly ran into some rough edges.
         | Especially with some of the more complicated one click
         | services.
         | 
         | Overall, I like it but I wish it was a bit more polished.
        
         | replete wrote:
         | Coolify will be great, 6 months ago however I experienced so
         | many bugs around docker deployments I just couldn't trust it
         | for production. Hopefully the new hires will make continued
         | progress because there are some pretty great workflows
         | possible. Already though, it is extremely cool to run your own
         | platform
        
           | chris_pie wrote:
           | There's also a long standing issue of random peaks to 100%
           | CPU, that they don't seem to be able to fix.
        
         | tharos47 wrote:
         | How do you handle backups ? I recently setup coolify and
         | installed the included WordPress. WordPress was broken by a
         | failed module install, I wanted to restore a backup and didn't
         | find a way to backup only one service/stack.
         | 
         | Compared to simply docker compose isolated in a vm/lxc
         | container it was not a particularly better experience.
         | 
         | I also wanted to use cloudflare tunnels instead of exposing the
         | server on the internet and it seems coolify really prefers to
         | work directly on the internet (lacking reverse proxy doc, ...)
        
       | __jonas wrote:
       | I've got a kind of similar setup but what I've been doing is
       | instead using a registry I'm just pushing the images along with
       | the compose file onto the server directly with rsync to keep
       | things even simpler. Would be nice to have a proper tool like
       | this to automate that (I'm just using a bespoke shell script).
        
       | qudat wrote:
       | I just use a tunnel service to self host web services, works
       | great and is cheaper than a VPS: https://tuns.sh
        
       | Nelkins wrote:
       | All of these projects lack server hardening. I think for most
       | devs it would not be a great idea to just point at a server and
       | let 'er rip. I have a pretty extensive cloud-init script I use
       | for this when deploying to a VPS. I workshopped it by finding
       | existing scripts and having a back and forth with Claude. Feel
       | free to roast it :)
       | 
       | https://gist.github.com/NatElkins/20880368b797470f3bc6926e35...
        
         | simpaticoder wrote:
         | Thank you for sharing, because I didn't know what cloud-init
         | was until your post. I've done something similar, but packaged
         | as a library of bash functions, designed to be called in
         | arbitrary order. I cannot comment on the specific decisions you
         | made in your file, but the fact that a declarative, compact,
         | and standard solution exists for this problem is music to my
         | ears. Out of curiosity, where did YOU learn of the existence of
         | this feature?
        
           | shortsunblack wrote:
           | Cloud init/Cloud config is a standard way to provision Linux
           | hosts. It is slowly being outcompeted by Ignition and the
           | friends, though.
        
             | mdaniel wrote:
             | > It is slowly being outcompeted by Ignition and the
             | friends, though.
             | 
             | I hope not, because I lack enough foul language to describe
             | my burning hatred for Ignition and all its cutesy campfire-
             | related project codenames. Hate-red.
        
           | simpaticoder wrote:
           | Looks like it was invented by Canonical for AWS/EC2 in 2006
           | (!). It was then gradually adopted by other clouds over the
           | next 10 years or so (GCP adopted in 2013, Azure a couple
           | years later). Linode (Akamai Cloud now, I guess) adopted in
           | 2023. Obligatory xkcd: https://xkcd.com/1053/
           | 
           | This got me to wondering _when_ I first heard about HTML,
           | HTTP, Linux, UTF-8, or any number of things, and from where,
           | how so many of the things I 've heard of once and never
           | again, and the many important "standard" things I've never
           | heard of.
        
         | wongarsu wrote:
         | There is a weird dynamic going on where defaults have become
         | "good enough": ssh with public key configured and password auth
         | disabled, services defaulting to only listening on localhost,
         | etc., but those improvements have also cause people to pay much
         | less attention to server hardening or to checking if any of
         | their services might have unsafe defaults.
         | 
         | The world is made much better by safer defaults, but they also
         | lead to a degree of complacency.
        
         | fragmede wrote:
         | port 22 and usepam is interesting. maybe set that to not 22 and
         | not use pam unless you have a specific reason to. didn't dig
         | deep to see if you had one but you're not setting a pam.conf.d
         | file as far as I saw. There's more to pick apart, but if that's
         | the best Claude can do my job is safe for 30 more seconds.
         | 
         | hire a professional to secure your shit.
        
           | computerfriend wrote:
           | Why not use PAM? Or is the issue the missing PAM hardening?
        
             | fragmede wrote:
             | why use pam when ssh has authentication built in? pam is
             | great if you have a reason to use it. I use it on my Mac so
             | I can use my fingerprint for sudo. turning on pam implies
             | you want to do something with it.
        
               | dizhn wrote:
               | I was recently evaluating pam_ssh_agent_auth . It might
               | be that. It allows sudo with a locally installed key.
        
         | notarealllama wrote:
         | Thanks for this, I still provision with a bash script.
        
         | Wilder7977 wrote:
         | I had a quick look, that "deploy" user can run any sudo command
         | without password? It's basically root at that point. I think
         | that forcing a password (maybe using some lax timeout if you
         | don't want to insert it so often) is a much better option.
         | Correct me if I am wrong, but I also see that there are secrets
         | in the file (e.g., gmail SMTP creds). Make sure the file is
         | protected in read at a minimum. If those are your gmail app
         | credentials, they are pretty serious and obtainable by just
         | reading the file (same goes for postfix config).
        
           | klysm wrote:
           | I've had this argument so many times over the years, and
           | usually the response comes down to security by obscurity
           | because people won't know the non-root username
        
             | Wilder7977 wrote:
             | That I guess is relevant in the context of brute-force
             | login, which given you only use key with, is not really
             | something I would stress over. However, depending on what
             | that user does, there might be vulnerable services running
             | with its privileges, or there might be supply-chain vectors
             | for tools that user runs.
        
         | codelion wrote:
         | server hardening is definitely an often overlooked aspect...
         | that gist looks comprehensive. i'm curious, have you
         | benchmarked the performance impact of all those security
         | measures? it's a trade-off, right? some community members
         | mentioned using CIS benchmarks as a starting point, then
         | tailoring from there.
        
           | klysm wrote:
           | Security performance tradeoff is hard, but I always try to
           | keep in mind what the downside to either is. A small
           | performance hit can definitely matter, but for most use cases
           | a security hit will matter a lot more
        
         | Timber-6539 wrote:
         | I wouldn't put some configuration values like no-new-
         | privileges:true in the global docker daemon config. Eventually
         | you will find some app that will break because of this and you
         | will spend hours troubleshooting it if you do not remember this
         | tiny detail.
         | 
         | Something also has to be said for simplicity and redundant
         | choices. For example replacing systemd-timesyncd with chrony is
         | not justified. And some of the recommended sysctl values may be
         | redundant and already the default in the target OS.
        
       | hn_rob wrote:
       | I have been using a makefile where each target executes a shell
       | script snippet to build, push or deploy containers. The problem
       | is that with simple docker build it doesn't recognize modified
       | code files and uses cached layers. To pick up changes in the code
       | I always have to build with --no-cache which is inefficient. I
       | wonder if Airo can detect changes in the code and rebuild only
       | the image layers that need to be rebuild.
        
         | globular-toast wrote:
         | This sounds like a misconfiguration on your part. I've never
         | had this problem with docker before. Are you sure it's not your
         | makefile skipping something because you haven't made the docker
         | bits phony targets (if you're using make as a "script runner",
         | everything should be a phony target. A sign that you're using
         | the wet tool, but I digress).
        
       ___________________________________________________________________
       (page generated 2025-03-09 22:02 UTC)