{"id":51004775,"url":"https://github.com/fabienpiette/schedule-containers","last_synced_at":"2026-06-20T19:01:57.279Z","repository":{"id":365878126,"uuid":"1274138848","full_name":"fabienpiette/schedule-containers","owner":"fabienpiette","description":"Schedule Docker containers on cron: start, stop, or wake on demand. Stacks, auth, and a dashboard. Single binary, no dependencies.","archived":false,"fork":false,"pushed_at":"2026-06-19T10:06:25.000Z","size":56818,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-19T10:26:27.157Z","etag":null,"topics":["automation","cli","container-management","container-scheduler","cron","devops","docker","docker-compose","go","golang","homelab","htmx","scale-to-zero","scheduler","self-hosted","sqlite","web-dashboard"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fabienpiette.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-19T08:03:42.000Z","updated_at":"2026-06-19T10:06:29.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/fabienpiette/schedule-containers","commit_stats":null,"previous_names":["fabienpiette/schedule-containers"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/fabienpiette/schedule-containers","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabienpiette%2Fschedule-containers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabienpiette%2Fschedule-containers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabienpiette%2Fschedule-containers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabienpiette%2Fschedule-containers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fabienpiette","download_url":"https://codeload.github.com/fabienpiette/schedule-containers/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabienpiette%2Fschedule-containers/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34581934,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","cli","container-management","container-scheduler","cron","devops","docker","docker-compose","go","golang","homelab","htmx","scale-to-zero","scheduler","self-hosted","sqlite","web-dashboard"],"created_at":"2026-06-20T19:01:56.036Z","updated_at":"2026-06-20T19:01:57.270Z","avatar_url":"https://github.com/fabienpiette.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/logo.png\" alt=\"schedule-containers\" width=\"120\"\u003e\n\u003c/p\u003e\n\n\u003ch3 align=\"center\"\u003eSchedule Docker containers on cron — start, stop, or wake on demand.\u003cbr\u003eStacks, auth, and a dashboard. Single binary, no dependencies.\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/fabienpiette/schedule-containers/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/fabienpiette/schedule-containers/ci.yml?branch=main\u0026label=CI\" alt=\"CI status\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/fabienpiette/schedule-containers/releases/latest\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/fabienpiette/schedule-containers\" alt=\"Latest release\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/fabienpiette/schedule-containers/pkgs/container/schedule-containers\"\u003e\u003cimg src=\"https://img.shields.io/badge/ghcr.io-image-2496ED?logo=docker\u0026logoColor=white\" alt=\"Container image\"\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/github/go-mod/go-version/fabienpiette/schedule-containers\" alt=\"Go version\"\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/fabienpiette/schedule-containers\" alt=\"License: AGPL-3.0\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/demo.gif\" alt=\"Demo\" width=\"600\"\u003e\n\u003c/p\u003e\n\n## Quick Start\n\n```bash\ndocker compose up -d\n# Open http://localhost:8080 — first run creates an admin account\n```\n\n## Features\n\n- **Cron scheduling** — Start and stop containers on any 5-field cron expression (`0 8 * * 1-5` = weekdays at 8am)\n- **Stacks** — Schedule groups of containers together with shared cron expressions and on-demand wake\n- **On-demand wake** — Wake stopped containers via `/wake/\u003ccontainer\u003e/`, auto-redirect when healthy\n- **Inactivity auto-stop** — Stop containers after configurable idle timeout (monitors CPU and network activity)\n- **Authentication** — Login, sessions, and three roles (reader, writer, admin). First run prompts for admin setup. OIDC login via Pocket ID or any OpenID Connect provider\n- **Tags** — Reusable schedule templates applied to multiple containers at once\n\n## License\n\n[AGPL-3.0](LICENSE) — a network-copyleft license: if you run a modified version as a network service, you must offer its users the source.\n\n## Install\n\n**Prerequisites:** Docker (runtime), Go 1.25+ (build from source)\n\n### Docker (recommended)\n\n```bash\ndocker compose up -d\n```\n\nPush to your own registry with `make docker-release`. Deploying with Portainer? See [`examples/portainer/`](examples/portainer/).\n\n### From source\n\n```bash\ngit clone https://github.com/fabienpiette/schedule-containers.git\ncd schedule-containers\nmake build\n```\n\n## Usage\n\n### CLI\n\n```bash\nschedule-containers serve                                          # Start server + scheduler\nschedule-containers schedule add my-app \"0 8 * * 1-5\" \"0 18 * * 1-5\"  # Add schedule\nschedule-containers tag add business-hours --start \"0 8 * * 1-5\" --stop \"0 18 * * 1-5\"\nschedule-containers tag apply business-hours --containers my-app,redis\nschedule-containers schedule export schedules.yaml                 # Export\nschedule-containers schedule import schedules.yaml --dry-run        # Import (dry-run)\n```\n\n### On-Demand Wake\n\nConfigure a reverse proxy to redirect to the wake URL when the upstream is down:\n\n```caddy\napp.example.com {\n    reverse_proxy app:8080\n    handle_errors {\n        @is_down expression {http.error.status_code} in [502, 503]\n        handle @is_down {\n            redir https://schedule-containers.example.com/wake/app/ permanent\n        }\n    }\n}\n```\n\nWhen a user accesses the container's URL while it's stopped, they're redirected to the wake page. The container starts, a health check runs, and the user is redirected to the running service.\n\n### API\n\n```bash\ncurl -X POST http://localhost:8080/api/schedules \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"container_name\":\"my-app\",\"start_cron\":\"0 8 * * 1-5\",\"stop_cron\":\"0 18 * * 1-5\",\"enabled\":true}'\n\ncurl -X POST http://localhost:8080/api/stacks \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\":\"my-stack\",\"start_cron\":\"0 8 * * 1-5\",\"stop_cron\":\"0 18 * * 1-5\",\"enabled\":true}'\n\ncurl http://localhost:8080/api/containers/my-app/health\ncurl http://localhost:8080/api/schedules/{id}/wake-url\n```\n\n### Dashboard\n\nOpen `http://localhost:8080` — view containers, manage schedules and stacks, start/stop containers, create and apply tags, configure on-demand wake. First run redirects to a setup page to create the admin account.\n\nFor all options: `schedule-containers --help`\n\n## Configuration\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `DB_PATH` | `/data/schedule-containers.db` | SQLite database path |\n| `DOCKER_HOST` | `unix:///var/run/docker.sock` | Docker socket address |\n| `WEB_PORT` | `8080` | Web server port |\n| `WEB_HOST` | `0.0.0.0` | Web server bind address |\n| `LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, `error` |\n| `TZ` | `UTC` | Timezone for cron evaluation |\n| `PRESETS_PATH` | *(empty — uses embedded)* | Custom presets YAML; if set and file doesn't exist, embedded defaults are copied to it |\n| `OIDC_ISSUER` | *(empty)* | Pocket ID or OIDC provider URL (no trailing slash) |\n| `OIDC_CLIENT_ID` | *(empty)* | OIDC client ID |\n| `OIDC_CLIENT_SECRET` | *(empty)* | OIDC client secret |\n| `OIDC_REDIRECT_URL` | *(empty)* | OIDC callback URL (e.g. `https://yourapp.com/auth/oidc/callback`) |\n\nOIDC is disabled unless all four `OIDC_*` variables are set. When enabled, the login page shows a \"Login with Pocket ID\" button alongside local password auth.\n\n## Known Issues\n\n- **Docker socket access** — Grants full container control; consider `tecnativa/docker-socket-proxy` for restricted access\n- **CLI doesn't hot-reload** — `schedule add` writes directly to SQLite; a running server picks up changes on restart\n- **OIDC auto-provisioning** — New OIDC users are created with the `reader` role. Admins can promote them or link them to an existing local account via the admin panel.\n\n## Documentation\n\n- [Architecture](docs/ARCHITECTURE.md) — codebase orientation for contributors\n\n## Contributing\n\nContributions welcome — open an issue or pull request. See [Architecture](docs/ARCHITECTURE.md) for codebase orientation; `make build`, `make test`, and `make vet` cover the common development tasks.\n\n## Acknowledgments\n\nThanks to all [contributors](https://github.com/fabienpiette/schedule-containers/graphs/contributors).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffabienpiette%2Fschedule-containers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffabienpiette%2Fschedule-containers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffabienpiette%2Fschedule-containers/lists"}