Jig [ jig ]
noun
a device that holds a piece of work and guides the tool operating on it.
What is Jig?
Jig is a dead simple deployment tool to automate routine work with Docker, Docker Compose, and Traefik to streamline running services on your own virtual servers with the following goals:
- Bring Vercel DX to own servers: Vercel is setting a standard for deployment tools for many years and aiming for anything less would mean disservice to everyone
- Minimize error human error via automation: It's very easy to forget one little command, skip a stop while removing a container and you get an error, start over and get sad. Automation solves this, but when bash scripts aren't enough stuff like Jig should be a great start
- Keep things fast: From one line deployments to keeping disk writes to absolute minimum streaming data whereever this is possible, it is important to keep things fast for the comfortable blazingly fast™ automation
- Stay practical: Single-container apps stay simple, while compose deployments let one upload describe a whole stack and selectively expose only the services that should be routable
Jig was heavily inspired by Zeit (older version of Vercel) and Exoframe.js with focus on self-hosting and being minimal whenever this is possible.
Installation
Installation is in two steps:
- Server setup: Run a startup script on the server to pull all relevant images and take off
- Client setup: Download a client and get authentication ready
Server setup
Docker is a prerequisite, so ensure docker is available and running on your server
DNS management is not builtin just yet so you need to point domain names you wish to use with Jig manually. 😔
Thankfully it's mostly a one-time thing and you won't need to deal with it later. With Vercel domains it's as easy as an example below, but it depends on your provider
vc dns add <your base domain> <sub domain> A <your server public IP>As a last infra part you'll need to open up ports 80 (http) and 443 (https). Traefik handles https redirection and Let's Encrypt http challenges so you don't need to worry about unsecured connections
Load and run startup\update script below
curl -fsSLO https://deploywithjig.askh.at/init.sh && bash init.shThis will load Traefik and Jig, then ask whether the Jig control plane should be exposed
publicly or only through Tailscale. The script launches everything and prints the
jig login command to run on your machine
If Tailscale is installed on the server, the bootstrap flow defaults to a private control
plane and configures tailscale serve for
the Jig API. Your deployed apps can still stay public through Traefik
Login command will look something like jig login loooooong+code keep it for later
Client setup
curl -fsSL https://deploywithjig.askh.at/install.sh | bashAfter that just plug in the command you received in Server setup stage and start deploying
Start deploying
Initiate a Jig project and create the config
jig initUse jig init in any project directory to
create the starting config. For a classic single-container app, add a
Dockerfile and a
jig.json. Jig will pack the project, send it
to the server, and build it remotely
jig deployUse jig ls to check that it is running, then
jig logs <name> or
jig stats to inspect the live deployment
For compose stacks, jig ls shows one stack
with child services underneath it. Target a child with
stack:service, for example
jig deployments logs my-stack:api
If the project contains docker-compose.yaml,
docker-compose.yml,
compose.yaml, or
compose.yml, Jig switches to compose mode
and deploys the stack with docker compose
{
"name": "my-stack",
"composeFile": "docker-compose.yaml",
"restartPolicy": "unless-stopped"
}For legacy compose projects you can point Jig at the primary routed service with
composeService. For newer setups, add
x-jig blocks on the services you want Jig to
expose. Services without x-jig stay internal,
which is how you keep things like databases in the stack without giving them a public route
services:
frontend:
build: .
x-jig:
name: frontend
domain: app.example.com
api:
build: ./api
x-jig:
name: api
domain: api.example.com
environment:
# Pull this from a server-side Jig secret named "database-url"
DATABASE_URL: "@database-url"
db:
image: postgres:16
# No x-jig block here means this service stays internal to the compose stackSecret values in envs use the same
@secret-name convention, so a service can consume
the same server-side secret whether it is deployed alone or through compose
Local image deploys via jig deploy -l still work
for single-container projects, but are not supported for compose deployments
jig deploy -lDelete a deployment with jig rm <name>. Compose stacks use the same command shape for child services,
jig rm my-stack:api. Rollback is available
for single-container deployments. Compose deployments are listed and deletable, but
rollback is intentionally disabled
Let Traefik fetch certificates if you deploy with TLS enabled and you're done