Run it on Dokploy
Deploy CareerBot's compose file on Dokploy, with self-hosted Convex beside it, click by click.
Dokploy deploys a Docker Compose project from a Git repository and routes domains to it through
Traefik. These steps were tested on Dokploy v0.30.8, deploying compose.yaml with self-hosted Convex in the same
compose, end to end: setup code, owner account, sign out, sign in.
Before you start
- A server with ports 80, 443 and 3000 free: Dokploy's installer needs them.
- DNS records for the hostnames below, pointing at the server:
careerbot.example.com,convex.example.com,convex-site.example.com, and optionallyconvex-dashboard.example.com. See DNS.
Install Dokploy
curl -sSL https://dokploy.com/install.sh | sudo sh
Open http://<server address>:3000. Register: First Name, Last Name, Email, Password, Confirm Password.
Welcome wizard: Get started > Create project (Name: CareerBot) > "Ship something" > SKIP ALL > Skip anyway.
Deploy CareerBot
- 1
Create the compose service
Projects > CareerBot > production > Create Service > Compose. Name:
CareerBot(the App Name fills in by itself). Compose Type: Docker Compose. Create, then open it. - 2
Point it at the repository
General > Provider. The GitHub tab needs a GitHub App set up in Dokploy's Settings; for the public repository, use the Git tab:
Field Value Repository URL https://github.com/careerbotdev/careerbot.gitBranch masterCompose Path ./compose.yaml(change it from./docker-compose.yml)Save. Dokploy builds nothing:
compose.yamlnames CareerBot's release images, which it downloads. - 3
Set the environment
Environment: click the eye to show the editor, paste these lines, Save.
COMPOSE_PROFILES=self-hosted SITE_URL=https://careerbot.example.com NEXT_PUBLIC_CONVEX_URL=https://convex.example.com CONVEX_SITE_ORIGIN=https://convex-site.example.com CONVEX_SELF_HOSTED_URL=http://convex-backend:3210 WEB_PORT=3001Dokploy writes them to a
.envnext tocompose.yaml(Create Environment File is on). Add any other settings from Configuration here too, such as Google and GitHub sign-in keys.WEB_PORTis needed because Dokploy's own dashboard holds port 3000. Without it the first deploy failed withBind for 0.0.0.0:3000 failed: port is already allocated. Traefik still sends traffic to the container's port 3000. - 4
Add the domains
Domains > Add Domain. It says "Services not found" until you click the refresh button next to Service Name, which reads the services from the repository. Then, for each row, pick the Service, enter the Host, set the Container Port, and turn on HTTPS for a real domain:
Service Host Container Port webcareerbot.example.com3000 convex-backendconvex.example.com3210 convex-backendconvex-site.example.com3211 convex-dashboard(optional)convex-dashboard.example.com6791 Create. Dokploy adds Traefik labels and puts these services on both
dokploy-networkand the compose project's own network, soconvex-setupstill reachesconvex-backend. Isolated Deployments isn't needed. - 5
Deploy
General > Deploy > Confirm. Dokploy downloads the images and starts them. Progress shows under Deployments. On the server, the log is under
/etc/dokploy/logs/. - 6
Find the setup code
Logs > Select a container: the one ending in
-convex-setup-1> typeSetup codein Search logs. - 7
Create the owner account
Open
https://careerbot.example.com> Create your account: the setup code, a username, and a password twice. You land on Today. Signing out (account menu, bottom left > Sign out) and in again worked in the test.
Deploying again prints a new setup code while there's no owner account yet, and the earlier one is refused. Tested: an older code got "That setup code doesn’t work. Check it in the install’s output, or make a new one.", and the newest one made the owner.
Commands on the server
new-setup-code and reset-password run in the folder where Dokploy keeps the cloned code. On the server, as root:
cd /etc/dokploy/compose/<app name>/code
docker compose run --rm convex-setup new-setup-code
docker compose run --rm convex-setup reset-password <username>
<app name> is the service's App Name in Dokploy. The .env there carries COMPOSE_PROJECT_NAME, so the command finds
the running project (tested).
Firewall
compose.yaml publishes WEB_PORT (3001 here), 3210, 3211 and 6791 on the server's loopback address only
(BIND_ADDRESS, default 127.0.0.1), so they aren't reachable from the internet; Traefik reaches the containers over
Docker's network. Keep it that way: Firewall.
Snags seen in the test
From the test machine (an emulated amd64 machine on a Mac), not expected on a VPS:
- Docker doesn't start after the installer restarted it: the old
dockerdprocess was still running. Stop it, delete/var/run/docker.pid, thensystemctl start docker. - The installer sits at "overall progress: 0 out of 1 tasks", or every container fails with "unable to apply cgroup
configuration … Failed to determine whether process is a kernel thread": add
"exec-opts": ["native.cgroupdriver=cgroupfs"]to/etc/docker/daemon.json, restart Docker, and run the installer again.
After this
- Your keys: Keys and accounts.
- Adding people: Sign-in and who can join.
- Updating: Updates, backups, export.