← Back to Guides

    Async Docker deployments to edge devices (without SSH)

    With m87, you can deploy Docker Compose stacks to edge devices asynchronously.
    You register a deployment once, and the device applies it as soon as it has connectivity — even if it’s offline, behind NAT, or reboots in between.

    There is no SSH access, no inbound ports, and no CI runner that needs to reach the device.


    The problem

    Edge devices are often unavailable when you want to deploy:

    • Devices reboot or lose connectivity
    • Devices sit behind NAT or CGNAT
    • SSH access is unreliable or intentionally disabled
    • CI pipelines assume the device is reachable now

    In these environments, “run this command on the device” is the wrong model.


    The solution: async Docker deployments

    m87 uses a deployment-based model:

    • You register a Docker Compose deployment with m87
    • The deployment is stored centrally
    • The device pulls and executes it when it has internet access
    • Execution state, retries, and failures are tracked automatically

    Once registered, the deployment remains active and reconciles over time.


    Quick start

    1) Create and activate a deployment

    m87 <device> deployment new --active
    

    This creates a new deployment and marks it as the active desired state for the device.


    2) Register your Docker Compose stack

    From the directory containing docker-compose.yml:

    m87 <device> deploy docker-compose.yml
    

    This uploads a run spec based on your compose file.


    3) Monitor execution and status

    m87 <device> deployment status --logs
    

    You can disconnect at any time — execution continues on the device.


    What happens under the hood

    When you run m87 <device> deploy docker-compose.yml:

    1. The CLI uploads a run specification to the server
    2. The device pulls the active deployment over its outbound connection
    3. Docker Compose commands execute on the device
    4. Results and logs are reported back to m87

    If the device is offline, execution starts automatically once it reconnects.


    Example: Docker Compose as an async service

    Below is a simplified example of a Docker Compose–based service deployment.

    jobs:
      - id: app
        type: service
        enabled: true
    
        workdir:
          mode: ephemeral
    
        files:
          docker-compose.yml: |
            services:
              web:
                image: nginx:alpine
                ports:
                  - "80:80"
                restart: always
    
        steps:
          - name: pull
            run: docker compose pull
            timeout: 15m
    
          - name: up
            run: docker compose up -d --remove-orphans
            timeout: 10m
            undo:
              run: docker compose down --remove-orphans
              timeout: 5m
    
        stop:
          steps:
            - name: down
              run: docker compose down --remove-orphans
              timeout: 5m
    

    This deployment:

    • Pulls images on the device
    • Starts the Compose stack
    • Automatically tears it down when the job is stopped or removed

    Updating a deployment

    To update the deployment, re-run deploy with the modified compose file:

    m87 <device> deploy docker-compose.yml
    

    m87 replaces the existing run spec and applies the updated desired state.


    Removing a deployment

    To remove a Docker Compose job from the active deployment:

    m87 <device> undeploy app
    

    Any defined stop steps are executed during removal.


    Rollback via deployment cloning

    To roll back to a previous deployment state:

    m87 <device> deployment clone <deployment-id> --active
    

    This creates a new deployment from a known-good configuration and activates it immediately.


    Async vs sync Docker workflows

    WorkflowUse when
    m87 <device> docker compose upInteractive development
    Async deployment (deploy)Production or unattended devices
    Sync executionDevice is online now
    Async deploymentDevice may be offline or rebooting

    Both workflows can coexist and target the same device.


    FAQ

    What if the device is offline?

    The deployment is applied automatically when the device reconnects.

    What happens on reboot?

    The device reconciles the active deployment after startup.

    Where do files live on the device?

    Files are placed in an ephemeral working directory unless configured otherwise.

    Are retries handled automatically?

    Yes. Timeouts and retries can be defined per step.


    Next