DAPPCON 2025: How to Create a Dappnodes Package For Your Node/Infra - Luka Gulin
DappCon 2025 · June 2025 · 53:15
Luka Gulin walks through how to build a DAppNode package for running Ethereum node infrastructure. Speaking at DappCon 2025, he covers the practical tooling behind packaging software for DAppNode, the open-source platform for running Ethereum nodes and related infrastructure at home. The talk treats node operation tooling as foundational developer infrastructure for Ethereum's decentralization.
Speakers
Topics
From DappCon 2025, hosted by Dappcon Berlin.
Transcript
Hey, good morning guys. So today I'm going to do a little workshop how to build a relatively simple DevNote package. Uh I hope that you know what DevNote is. So that's why you're here but I'm wondering whether you have done anything on DevNote any of you. All right. And and that that's not that important. The important thing is for you to be able to follow workshop uh you need to be familiar with docker a little bit. Okay. So I I'll show I'll show the flow. So my idea is to make a make a package like live in front of you and uh that it's not like crypto package because node is
more than a than just like a staking machine. You can do much more. It's your own server. So you can do whatever and um I had the idea of doing the um Osis package. Osis means on cloud infinite scale that's the newest product uh new newest release of of on cloud opensource service. So I can show you. So idea my idea is to build this as a deput package. So that's your own uh cloud storage that you host. You don't share with you don't share your data with anybody and it's completely
private. So depode can do that and can do that easily and and I'm going to de demonstrate you. So I I'm going I'm going to show you like real process how I do it. uh and it's a bit of iterative process because at the front I don't know what's what's going on what are the package requirements and it's a bit of a um to try trial and error situation. So first uh for for us to be able to do a package easily uh we would like that the package has its like official docker docker image and that that simplifies
process massively. So if you the the the easiest way to to find that is to go to the docs of a package and go to for example deployment and try to find uh some some kind of ba basic setup or getting started or something that that uh that shows you how to run run this first with docker and then and then um like within the dev node. Okay, I I found this this this in docs uh which which redirects us to this which redirects us back to the same
page. Okay, I think it's in basic remote setup. So, docker compose development examples uh basic I I I found this day ago. So, we need so we need docker. Let's do it do it like this. So, discover ois with docker. Yeah.
Yeah, this is it. So the these are the Osis docs. We are still not doing any any devote related stuff that tell tell that tell us how to uh deploy Osis with Docker. And if we scroll down a bit, it tell it tells us to prepare directories. That's fine. To do the uh to change ownership of of uh directories, that's fine. We don't care about that. We care about this docker pull. Okay, we need to pull the image and we need to run this docker command which in initializes the osis and then we have to run this bigger command that
that runs osis indefinitely. So that's a that's like bit of anti pattern in depth node because in depth node we just want it like to start run it and that's it but we can solve that. So let's now now that we have the idea how it works we can we can go to the to the own machine and we can choose the folder uh where where we are going to build stuff. So in on my PC I do it in code the definite folder it doesn't matter and let's create um let's create the folder where we are going to build our project in so as a standard uh we name them like this devote package
dash whatever name of the project is let's call it osis so we we change to that folder And now we start start uh coding. So we have tool called node SDK that's meant to to facilitate this process. And first thing that we need to do in this folder is initialize node repo. So we use deposate command but we won't publish anything still and we will do init command
and this will us this will guide us now through the defaults we will use the uh package that's default from the folder name we we'll use version we we will type in description later I I'll tell you where these fields are for order we'll put a dep node license GPL 3.0 zero doesn't matter right now. And that's it. We are now initialized and we can open our ID. Thank you for and now we have basic structure of our dep node repo. uh we start for docker file
because that's the that's the first thing we we see and we what we do with the defo package is we just take take the whatever we are doing whatever package we are doing in this case osis we take take that that image as a base base base image to to our own image that we are building with the depth node. So you see here we have we know that u name of the image is on cloudtosis and what we do is is we we say from on cloudosis that that that means that that our entry point is don't
cloudosis official image but um we won't have version tracking of this because when you do this this will pull the latest image and then you won't know what you're doing. And then what we stand do is we tag them and we always use uh uh upstream version um variable but we need to define that first and we we will define that in docker compose. I'll tell you later why but here we just need to like declare it and and we declare it as
uh argument option version from Osis cloud and that's it from uh for now uh what we ch what we need to add here is that uh uh that um that up version variable here it won't be version it will be upstream version and we want it to be the latest one there is so we'll just Google it
okay not like that so we'll just Google it and we'll see what what's the latest version because we want to build on top of the latest version there is no sense in building anything else and that's 7.1.1.3.3 and we defined it that 7.1.3 and this is our like basic basic setup. So what we can do now is we can try building this. Obviously, it won't work because we we saw here that we uh first need to run this init in init command. But it doesn't matter like we can we can just um try building it. And now um my connection to the dub
node is broken because I haven't connected to the VPN. So what what build command does is uses your docker to build the package and then to uh upload it to IPFS. If you don't have IPFS endpoint, you can't do it. But luckily, so I have that here in my wire guard and I can connect to it. So if you're following with me uh if you're trying to do uh No, no, it's fine.
So So if you're following me and you want to do do this with me, uh there there is way to do this without having to connect your your dev node. So what you then have to do is you have to uh uh you have to add anal argument variable which is called provider which is IPFS provider and then you write either like http of uh IPFS API or you you use like our our own that's that we use for developing but we often purge it. So you you cannot count on it. So we call it remote.
And if you do this, this will work even without connecting to your D node. But as I'm connecting to to my DNA, then I don't need remote provider. I can just use that node SDK build. And now it's a building an image and it and and it takes a while. And what while uh it's obviously uh already built because our Docker file is very simple. Uh so it just now saving and compressing and later it will upload it to IPFS. So this obviously won't work because we didn't but I I'll I'll show you the process till till the end at least now and then later we will iterate it more quickly. So while while this happening
does anybody have any questions? Is anything clear? Everything clear. All right. So, um we can wait while so this this is being built. Uh and while while that's going on, we can see here uh in more detail what we need to do. So, first we need to init this thing and then and then we will get some kind of user and password. I don't know right now what that is but we will figure it out. All right. So it it it has been built very quickly and it has been
uploaded to to my IPFS. So I I uh from here I can I can try to install it on my dev node. So I I've got the link here and I can follow it. So this is uh this is opened on my dev node and it's and now it's try it will try to load it. quite simple. But let's let's do this. This is irrelevant to the This will make it load more quickly, I hope. Yes. So, I have the basic package now built. It it it has it doesn't look
very pretty. It doesn't have a It says that release is not signed, that it's unsafe. And if you try to update it, you won't be able to because you have to check the advanced options to to bypass uh restrictions that we have. These these restrictions are because um when when users are mostly using DAP node in order to stake and to validate and they have validators and everything and um since the SDK is permissionless uh and anybody can create dab packages um anybody could just create a package that's called Prism consensus validator
for example and people would just download it thinking that it is but if it's if it's not signed by the original poster of um the prism package then it it will not be it will not be accepted. So packages include a signature by with the developer key and the dab node can recognize when somebody is trying to impersonate another package that's not been signed by the uh developer address that's allowed to sign this. Yes, exactly. Uh so the dev node uh philosophy is you can do whatever you want uh you can install whatever package do you want but but we want want u uh you to know what you are doing so it's not
signed that means it's it was it has been released by whomever but you can install it and you do you do it on your own risk but we have like very robust system that that that tells you from us uh that the package is signed and then you then you can I mean tr trust the author either us or developer of that package whoever that is. So I'm going to try to install it now. Um I I will click on update because uh I I already have like specosis and it will try to um install it and uh first that we do when we install a
package is we look at the logs and see what's wrong because on first try it's it's almost certainly going going to be something wrong with it. I mean we are on purpose doing something wrong wrong right now but but yeah the that I I want to I want you to show the process because I I've never I've never built a package in the first try. So yeah I want to show you have this. So if you go to the logs, so yeah, it's it's it's like giving me some weird error and nothing works because when we go back to the docs, we have to uh do first time in
initialization and uh here we see that we need to provide it with two volumes. So uh we will do that right away. First volumes are both same in this docker run and this docker run command. So we can safely mount them. Uh so what we can do is we can write volume command and my copilot is telling me what to do I think almost correctly because I don't want these to be um bind mounts. I want to be the to be these to be real docker volumes. So what we do that that this is basic docker
stuff. This has nothing to do with node. We just specify these volumes and and um and declare volumes here as is per docker spec. What devote SDK for some some reason wants is that you add these uh empty brackets to it. So so your validation passes. All right. So this is the the this part like m this mounting part and next part what what we need to do is this own cloud in it in it uh step and um uh since we need to do these both steps
inside of the docker volume the dep node package and without without interaction with the user. So what we do is usually uh we uh write a simple bash script that help us deal with that and and usually we call it entry point.sh. So I will create create that. I will make it executable. And now we can um we we can uh route our uh entry point script.
So, but because we've wrote our entry point script, we would need to change our our docker file. So, it it it's not as simple as it was few moments ago and then we will change it. First, we will set uh work directory to the uh standard one in dev node. It's user source app. This this is irrelevant from the devote devo perspective. We would need to change uh we would need to copy uh our entry point to the destination and we we have to specify now with the
do uh docker command entry point that our entry point is the entry point. Yeah. And this is our docker file that we are going to use. Ah so thank thanks. So that's pretty much it for our docker file and all all the complex complex logic uh happens here. So let's save our docker file. We saved our docker compose and in the entry point um we we we try to do what was what's been done here. So these are two steps. So
one is that we need to in it and second step is that we need to run it like this. So first step is as I said osis in it what what what's the name and it says in we need to do it with insecurius so what this means for like I don't know for right now but what we can do is what we we can um uh SSH for example some Linux machine and then we can we can try docker run
okay for example help you it can't find the image but it will download it and then this is help command so maybe we can do osis init help and this tells us uh usage of the init command. So it says uh options that we have and their default values. So allow insecure osis config that down sounds that doesn't sounds uh benign but uh it's okay because
everything is uh tucked in in docker. So we don't need to worry about it. But it says um admin password and set admin password to find using random generated one. So it says here that when you are doing OCIT command that your password is random randomly generated if you don't send admin password value and that's something that we do not like because that would need users wouldn't be able to set their password and their password would be they they would like have to fish it out of the logs. So that's that's not uh uh very optimal. So so what we can do is using this OCC
command we can set admin password to to some value and let and uh and let's call that value odd and password. So so that's some some kind of variable that that user will be able to set. So in that node we interact with the packages using environment v variables mostly. So what we do is we need to set this environment variable and we do that in docker compose. So docker compose is a file that dep node reads and builds your interface around the depo package around it. So wherever whatever environment variable is defined
in the compose it is shown on the UI. So environment admin password equals let's do it like this. We we will set it empty so that that user is for to set. Yes. Zoom in. Oh okay. So uh I will zoom in. So the question was can I zoom in? Yeah definitely. Is it better? Yeah. Yeah I can do it even more if you want. So yeah uh right now we have our entry point set uh environment set to that we need to insert admin password and we are doing our OC in it. Nice.
Next uh after we've done OC in it, we we we need to um we need to uh do this command and this command is bit tricky because it is using default entry point and we don't know what that is but we can easily find out in uh for example for the Os is easiest to do it in the GitHub excuse me Docker Hub and you You can see here that uh entry point default entry point is Osis. I'll zoom it and the command is server. What that means what we can do is we can do just Osis
OC server and that should be good enough except uh the the rest of the environment variables. So um for running Osis we need to expose the port. It says 9,200. We'll set the default. We don't have reason to change it. So we can expose the port. Uh actually we don't uh let me backtrack on that. We we don't uh in in def node. So how dev node works is that you are you are connected to your own network uh to so so when you connect to that node you
connect to the internal docker network of a of a dep node so you don't have to expose the ports but to to be able to access every every possible port of the of of the container. So, we'll skip this one, but we would need to um copy these environment variables. So, we'll need to figure out what what these are, but let them copy for now. So, OC in secure equals true. We've already said that uh proxy HTTP proxy address this uh to keep this more dynamic the HTTPS
proxy address is the address on which internal uh process is going to listen in Osis. So because the default port is 9,200, we'll set it to 9,200 and 0000 means that Osis will listen all interface that that are available to them. And that is a requirement where you are doing anything uh docker related. And this this last one osis URL is interesting one because it it makes us set URL that we will be accessing Osis from in advance and um u so when you install a docker package
it automatically uh gives you domain names for the for your package and I can tell you if you if you do public package which this is so if if you go go over Here it says Osis public package and this is actually domain that you you you are able to to connect to your uh package whatever you do. So what we can do here is we can just copy paste that there and we should be set. All right. So we've we we can uh double check we changed the environment. We did the volumes uh and that's pretty much it. we did in
it. And yeah, what we can do next is we can try to build the package again and see if it works. Yeah. Build again. Uh it has been built very quickly because this Docker file is extremely simple. But it doesn't matter that it doesn't it doesn't mean that that everything is going to go smooth. So what what's the next step of process is we iterate as I said. So we built a package we think it's it could be good.
We install it and see what's going on. So as before while we wait for this is there any question. All right. It should be done very quickly as it is pretty lightweight package. I think we have it here.
And you see uh in the package UI it picked up the uh version of our package and the upstream version because because uh DevNote understands upstream version argument in the compose. So we have it here. We can have it installed. It's again not signed. We we can uh bypass safe disclaimer. But what I'm going to show you is usually when when I mean building a package, I usually click this show advanced editor and that advanced editor shows shows us what we have set in the
in in the compose over here. Right? We have four environment variables. We we have this set and uh his volumes and and we do not want mount custom mount path. We want a default and we we what we need to do is set the password. We can set it as devcon. And then now it's in the plain text but but we can change that later. So accept save and it's it's been installed.
it. So because I'm using my own deaf node when I'm building a package and uh and package gets uploaded to IPFS node of my de node it doesn't it it it gets downloaded very quickly because it's it's on the same machine. So yes so we have it installed. Let's see logs. All right, it says that it generated uh Osis config. That seems fine. Let's try to go to the OS URL we specified here and see if it's going to work. Okay, so this connection is not private that uh that's happens because
we are using HTTPS here but and then we have to go around this. So this is limitation I found. Yeah. And then we we have our own own package. We can go admin Dcon and we're in. So we we we build like version zero of our package. So this is only right now this is only accessible for around dub node. It has this DNA private uh domain and you can use it. it has it has this uh ugly warning that your uh connection is not secure and as
I said that's Osis thing because it forces us to have https connection uh wherever so in depth node when so uh so when you are accessing your depth node you are uh we build it that you are either on VPN you are on the private Wi-Fi or you are using tail scale which is also kind of VPN. So necessarily it's not required uh to to have HTTPS connection for you to be safe. So-c because you are in a sandbox secure environment and uh usually when we build a pack we build packages uh we do not use https for example we
have I have rod key here and when I click on the UI here you see rod key here is is not using https it's not shown but it's not using hp but if we try to do the same thing with tossis Uh for example, if we change URL, we want it to be HTTP and update it. This will now change the environment variable and restart the package. Yes. Sorry, can you can you hear my microphone please? Sorry. One thing I didn't follow. I might have missed it early on. Um this dot dot node address.
So you're access you're on your laptop. Yes. there and you're talking to your node. Yes. How is that resolving? Like how is that? Yeah, because we are using I'm using um VPN here uh which is connected to a my node and when you are using VPN you can set up on your DNS server and that DNS server is also a deote package you can see it here and it it's made to resolve uh in this case uh docker aliases and the every every package install has has has uh docker aliases ends with the dev node your main uh uh your main UI this is called we call de manager has my dev dev
node domain and that's how are those resolved okay got it any other question all right so now we can see that our package is crashing it can't start and it logs so yeah could not create config config file already exist lists. All right. So that's a bug with our package. So what we did is we we we just in our entry point we just did OC in it and OC server. But so we have two solutions to this. We can uh use force override flag or we we can do do some
ifs in here if we want to if if you want this to execute only once. For example, we can check for a file and if that file exists, we don't do it. And if it doesn't exist, we we we do o OC in it and initialize the file. But in this case, I think it's better for us to use this force over override flag because in in other case the init file in it will be run only once and in in case we change our admin password, this won't be run again. So I think it's better to do do force override here and then when we change in our config admin file this
will this in it will be changed again. So yeah, let's do it like that and we can uh rebuild our package. But there is uh but because this um this config file is baked into our volumes. What we can do is we can now remove the volumes and that will uh that will fix our issue because we deleted our uh uh config file. But that's just temporary so we can see what's going on.
Now we have different error. So, so this is this is this is one I I was aiming for before. So it says in um ISS value URL must start with HTTPS. So um uh Osis is forcing us to uh do HTTPS and that's why I did it here uh first time. So we can update this delete volumes and now we should be up and running again.
So let's see logs admin. I don't see any logs but yeah the same warning again. Visit the website visit. Okay, we are good. So, uh what we can do is we can um uh we can uh install the fixed version of our package now that has force override flag set but I want to show the show a couple of more things. So, we won't be installing this one. We will installing next iteration.
So uh as you saw uh when we did docker in it it it gave us couple of those default files and one of those is this docker package file uh we which tell tells depth node whatever we have in info in info here but we have a lot more um lot more um possibilities Here what we can do is we can specify UI here. So UI here is HTTPS.
Uh what was it? What was it? This one. So we want users not to guess the guess the uh is it is guess the URL where where's stuff happening? And just to have like nice link here also we can do description of a package. This shows up when we are installing. But to to see the full possibilities here, we can go to the DNO docs and we have devs section and the the and the most useful to me is this file references section because it says
docker compose. We have that manifest. That's we have that as well. So there are a lot of uh uh lot of possibilities here. These are pretty straightforward what you can do uh architecture that you want to be be built the requirements dependencies types descriptions upr version whatever but I want to show you the setup wizard when we're installing the package. So uh the we we typed in the um environment variable that's called admin password bit sketchy. It was in plain text and that's something that you don't
do. That's why we have this u setup wizard that's a dedicate that's y as well that that uh builds us our setup wizard. So it package installation process is a bit more presentable. So we have example here that I'll copy and I will create a set of wizard here and I'll paste it and we'll change it to to to to our needs. So what we want to do with the setup wizard is have nice field to set admin password in. So ID is uh not relevant that much. We will call
it admin password for example. So what's what's our target? Our target target is environment and environment name and name of the environment variable is admin password. So we go to setup wizard we change that to the admin password and service is this. So that that refers to the docker service docker compos service that that we are aiming to inject environment variable to. So we change that to service title uh osis UI admin
password. So description of that variable is I don't know whatever whatever copilot said yeah it's uh secret is true we do do because secret that means that will be masked on the UI this is pattern that that uh we want it to match we don't want it to match any pattern it's not anom it's just a string So, so, so we just need these fields to be set. We want it to be required. We want to be secret and we want to be like
this. So, let's build build the package again. So, it has been built very quickly because we just added another file. We didn't change the old ones. So we can install it. So it's still not signed. We can bypass that. We can update it.
And now we have this that we that we just built. It says OCUI add password. And the password and this is what what we wrote here or what AI wrote for us. And that was devcon. We can submit that. We can accept that. And remember that we did two things here. We added setup wizard and we fixed the bug about force overwriting the config. So now when we install, we expect this to be working. And also we we added the UI link.
All right, we have UI link. Let's see logs. Okay, logs are still still a bit sketchy because they show uh password in uh in plain text. What we can do is for example if we don't want to do that if we want uh password to be bit more secure we can uh for example uh pipe this output to dev null and that that will hide the this output for example but since there are no logs let's see if our UR is working yep oh something weird
Let's see what our log say. You put dev node dev null. Yeah, but but this is Thank you. But this is just on my local machine that's not on the package. But yeah, not like that. Yes. So yeah, there is some kind of a login issue. Yeah, let's try to do it like this. Okay. Admin wait
the okay maybe we should we should have uh done this admin colon Yep we are back All right. So, we had issues with the HTTPS that's pretty pretty annoying and also your own cloud backup service is not that useful if you can reach it from anywhere and we have solutions for that. So, as a part of the node core core uh system we have something called HTTPS. So that's the package that that we we we maintain
and that's made for easily ex exposing your your internal services to to the wild to the internet and it it's made that you do it with the HTTPS always and how do you do that is you go to your Osis instance you go to network oh it's it's already done so because I've done before but let's remove it and what what you can do is you can create a HTTPS domain mapping so you create a new mapping and you choose a so subdomain so we want this to be for example Osis and uh which port do we want it to to connect to uh we saw that port is 9,200
and these are uh optional fields that use HTTP basic authentication for for you to be even more secure but since OS has It has its own um uh authentication. We don't need this. So we click add mapping. Yeah, I don't know why we got the error, but uh OC mapping succeeded. And we have an error here. Client sent an HTTP request to HTTPS server.
Uh so so we have toi fix this. And I'll fix fix it quickly because we are running out of time. First, what we need to do is change the uh domain name in the Osis to uh to match our our our domain view that we are mapping to. That's a limitation of the of the OCS itself. So now when we build the setup wizard we have for config we have this nice uh nice UI but we need the advanced editor for this because we didn't specify rest of the environment variables. So we update here and in the in the uh uh in the compost file we need we need
to change change our like default OC server not to be run on HTTP S but on HTTP. So we need to add here another environment variable that's called SSL insecure. Oh, sorry. SSR insecure equals false sorry SSL in. This is false and proxy TLS equals false.
So and when we build a package like this, it should work with our external domain. So this disables the TLS or OC server, but there is a there uh there is a high requirement for access to Osis to be on HTTPS. So what I said before is still true. We need HTTPS but uh to access it. But but the uh SSL termination can be either on OC server or somewhere upstream but what it wants is SSL for some reason.
So so yeah this is the basic guide how to build a working package. Uh there is a couple more things I I wanted to talk about. So there there we for for example when we are using this SDK we have tooling that help help uh help it maintain for example uh that there is automatic uh tool that does bumps on your GitHub actions that you don't have to follow the these upstreams always it it automatically it automatically opens you a PR and stuff like that but this is the basic stuff what you know what you need to do when you're building the package. Okay, let's
install it one uh one one last time. Let's click up advanced options. Let's update it. Accept. Accept. And here we go. So, let's for for last minute let's talk. Okay. When we when we build the package, what do we do? How do we publish it? We we use our our SDK. We call the publish command. But and for some reason we always have to say what we are bumping to. So we have either bump it to major minor major minor or patch version. But since the package new we don't that's not important. We can do major.
And now this this is uh doing uh similar thing but it will give us a link how to publish our package. Now now we have it here installed. I delete the volume so we are fresh. So there is no there is no left leftovers from before and we would expect out this to work on our servers but it doesn't. Yeah, the proxy. Oh, for some reason this is it has not been set properly for proxy ls false. This should be true.
Update it. Let's see the logs. Updated. Yeah, here we are. And the what what's good about this this is publicly accessible now. I can disconnect from my wire guard and it's still working. So you have like your own cloud in the not cloud but at home.
And yeah, uh with the and yeah, uh last thing that that's left is is to show you how the how the publishing works is that you connect to the your uh VPN, you do the release, and then this gives you everything you need to know when you're going to publish. gives you a link that you can publish it to gives connects it gives you prompt to connect your MetaMask to sign the release and if your signature is uh trusted it will um it it will show up on the on on the
UI sign. So I don't have a a wallet in Safari but that's pretty much it. Excuse me. I I can repeat the question. Thank you. Uh so how else can uh publishers sign releases? So I I can show you quickly. Let's go here in Chrome. I do I hear uh so you connect your wallet.
We want user IP. We want to watch So we will use some test net wallet. We can connect ah I don't know why it's asking me for rabbit. Uh yeah uh I don't want to use Rabi but yeah uh it's just like ordinary signing process you sign the message this is my package this is my wallet and you sign it and that that signature gets added to IPFS
IPFS package and that that all gets published on the uh ARM repo manager that that call host the version and IPFS cache and when you see it in your dev node it shows up said sign. Do you have a support channel? Yes. Where? In Discord. Thank you. Any other question?