Skip to content

ShipwickProduction deployments on your own server.

For developers and small teams with a Linux server of their own. One small file describes your application; one command builds it, ships it to the server and serves it over HTTPS, with health checks and automatic rollback.

A laptop sends a container to one server, where Wick, the Shipwick flame, keeps watch
Four stations from left to right: shipwick init writes the files, shipwick deploy builds and sends the image, the health checks pass, and the application answers at its address
  1. shipwick init
  2. shipwick deploy
  3. Health checks pass
  4. https://your-app

Five minutes ​

A Linux server you can reach over SSH, a domain that points at it, and your project on your laptop, with Docker running there. That is all it takes.

1

Install the CLI ​

On your laptop. One binary, shipwick; with Homebrew it is brew install shipwick/tap/shipwick.

bash
curl -fsSL https://get.shipwick.com | sh -s -- --cli
2

Install the server ​

From your laptop, over SSH. It installs Docker if it is missing, then the agent, the reverse proxy and the dashboard, and saves the API token for you. --agent-domain and --dashboard-domain give the API and the dashboard their hostnames.

bash
shipwick server install [email protected]
3

Deploy ​

In your project. init writes a Dockerfile and a deploy.yaml for it. deploy builds the image on your machine, sends it over and replaces replicas one at a time, each after it proved healthy. No registry needed.

bash
shipwick init
shipwick deploy

What a deployment looks like ​

A terminal showing shipwick deploy pulling an image, starting a container, passing health checks, routing https://api.example.com and finishing in 6.1 seconds
The version that works keeps serving until the new one has proved itself.
yaml
# deploy.yaml
name: my-api
build: .                  # built on your machine, sent to the server
port: 8080
domain: api.example.com   # served over HTTPS, certificate included
replicas: 2
health:
  path: /health           # traffic moves over only once this answers 200

The file above is the whole configuration: where the image comes from, the port it listens on, the domain, how many replicas, and how to tell that one is healthy. The certificate is obtained on the first request.

Already have an image in a registry, as in the picture? Name it instead of building: image: ghcr.io/company/my-api:1.4.2. A built frontend needs no container at all: static: dist/, and the proxy serves the folder.

Everything a small production needs ​

Deployments that undo themselves ​

One replica at a time, each after its health check. A version that does not come up never takes traffic; the one that works keeps serving.

HTTPS with nothing to configure ​

A certificate for every domain, load balancing across healthy replicas, aliases, www redirects and compression. Static sites are served by the proxy itself.

Migrations, cron jobs, one-off commands ​

A command from the new image before any replica starts, scheduled jobs from the same image, and shipwick run my-api -- rails db:migrate for the one you do by hand.

Databases, with backups as plain files ​

Volumes for the things that keep data. The server backs them up on a schedule, encrypted, to an S3-compatible bucket, and shipwick backups verify proves that one restores. shipwick backup downloads a volume as a tar file.

Secrets on the server, access with limits ​

shipwick secret set keeps a value encrypted on the server and ${NAME} fills it in on every deploy. A deploy token for CI, limited to its applications and with an end; your company's accounts for people; an audit trail of who changed what.

A dashboard, a CLI and an API ​

Replicas, health, a week of CPU and memory, history, live logs and what a crashed container printed last, jobs, backups, secrets and access, for one server or several. Whatever one of the three does, the others can.

The overview of the Shipwick dashboard: a sentence that says four applications need attention, the alerts that hold, and the applications with what is wrong with each
The dashboard: the same information as the terminal, live, with the everyday actions. It opens with the answer to "is everything fine?".

Two applications and a database ​

Applications reach each other by name on the server, postgres:5432, and nothing outside the server can reach those names. Several applications live in one shipwick.yaml.

yaml
# shipwick.yaml
apps:
  - name: postgres
    image: postgres:17
    port: 5432
    env:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}   # filled in when you deploy, never in the file
    volumes:
      - name: data
        path: /var/lib/postgresql/data
    health:
      tcp: 5432
    deploy:
      strategy: recreate                        # a database cannot run twice

  - name: api
    build: api                                  # built on your machine, sent to the server
    port: 8080
    domain: api.example.com
    env:
      DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@postgres:5432/app
    health:
      path: /health
    pre_deploy:
      command: ["./migrate", "up"]              # runs from the new image before any replica starts
    after: [postgres]                           # not before the database is up

  - name: web
    static: web/dist                            # served by the proxy, no container
    domain: example.com
    redirects: [www.example.com]
bash
shipwick secret set POSTGRES_PASSWORD     # once; asked without echo, kept encrypted on the server
shipwick deploy

postgres and web deploy at the same time, api once postgres is done. If one fails, what depends on it is skipped, the rest finishes, and the one that failed keeps running its previous version.

One server, on purpose ​

A single server is a lot of computer. A few cores and a few gigabytes of memory run the 1 to 20 applications of most products with room to spare. What such a server lacks is not power but the platform around it: deploying without downtime, restarting what crashes, rolling back a bad release, serving HTTPS, keeping secrets out of files, running the nightly job, taking the backup.

Shipwick is that platform, built for one server on purpose. One process, one SQLite file, one YAML file per application, and nothing to keep alive besides the server itself. It schedules nothing across machines. When one server is no longer enough, you have outgrown Shipwick, and the deploy.yaml you wrote says everything about the application that the next platform will ask.

One server with several applications inside it, a shield in front, and Wick keeping watch

For the people who run it ​

Everything above, with the details an operator asks for first.

What is on the server ​

Three containers from /opt/shipwick/compose.yml: the agent, Caddy and the dashboard. The agent's state is one SQLite file, shipwick.db, with its encryption.key beside it in the agent-data volume; certificates live in caddy-data, the folders of static sites in caddy-static. No external database, no queue, no second server.

Security ​

The agent holds the Docker socket, so an admin token is root on the server: treat it so, and give CI a deploy token. The API speaks plain HTTP on 127.0.0.1:9000 and is reached over HTTPS through Caddy, an SSH tunnel or a private network. Only the SHA-256 of each token is kept, env values and secrets are encrypted at rest, no shell runs anywhere, and containers are never privileged; security in deploy.yaml takes away more, per application. Application containers do not reach the API, and releases are signed by the workflow that builds them. People can sign in through your OpenID Connect provider, and every change is in the audit trail.

One API, three clients ​

The dashboard, shipwick and curl use the same REST API under /api/v1, and every endpoint is registered with the role it needs: read, deploy or admin. A deployment's request body is the deploy.yaml itself, and the agent validates it again whatever the client checked.

Install ​

On your laptop or in CI, the CLI:

bash
curl -fsSL https://get.shipwick.com | sh -s -- --cli

Or on a Linux server with Docker, as root, the server itself:

bash
curl -fsSL https://get.shipwick.com | sh

The CLI also comes with Homebrew, brew install shipwick/tap/shipwick, and on Windows with one line in PowerShell, irm https://get.shipwick.com/windows | iex. With it installed, shipwick server install [email protected] --agent-domain agent.example.com --dashboard-domain dashboard.example.com sets up the server over SSH, saves the token for you and prints the DNS records to create; shipwick doctor checks the whole setup afterwards. Everything the installer downloads comes from one release and is verified against its checksums. A server with no connection is installed from one file, and the agent also comes as a Debian and an RPM package.

Wick, the Shipwick flame, waving

One file, one command, and the version that works keeps serving. Your first deployment is one page away.