Skip to content

Repository files navigation

devops.local

English · Русский

Private LAN platform for one Debian/Ubuntu box: HTTPS portal, message queue, cache, databases, Docker registry, CI runner, Maven and Debian repos. Ansible + Docker Compose, no cloud.

Host: devops.local. Portal: https://devops.local/ (English by default, EN/RU toggle). Trust the CA once: http://devops.local/ca.crt.

Service portal

RabbitMQ PostgreSQL · Adminer
RabbitMQ Adminer
MongoDB · express Maven · Reposilite
Mongo Express Reposilite

Debian APT

Web UIs sit behind nginx HTTPS. AMQP / MQTT / Redis / Postgres / Mongo / Elasticsearch stay on native ports.

URL
Portal https://devops.local/
CA http://devops.local/ca.crt
Portainer https://devops.local/portainer/ (admin)
Registry UI https://devops.local/registry/
Registry API https://devops.local/v2/ · docker login devops.local
RabbitMQ https://devops.local/rabbitmq/ · AMQP :5672 · MQTT :1883 · WS :15675
Redis Commander https://devops.local/redis/ · Redis :6379
PostgreSQL https://devops.local/postgres/ · :5432
MongoDB https://devops.local/mongo/ · :27017
Elasticsearch https://devops.local/elastic/ · :9200
Maven https://devops.local/maven/
Debian APT https://devops.local/debian/
Gitea MCP http://devops.local:8080/mcp
Local Gitea http://devops.local:3000/ (optional, GITEA_ENABLED=true)

Docs: Maven / APT · databases · TLS / docker login · Gitea.

docker login devops.local
docker tag myimg devops.local/myimg
docker push devops.local/myimg

Stacks

Stack On the host What it runs
devops /opt/compose/devops runner, MCP, Maven, Debian, registry, Portainer, TLS/CA; local Gitea if GITEA_ENABLED=true
middleware /opt/compose/middleware nginx portal :80:443, RabbitMQ (+MQTT), Redis, Postgres, Mongo, ES

Each service is optional (make setup toggles / .env *_ENABLED). Compose profiles follow those flags.

Runner / MCP always use gitea_instance_url (existing Synology Gitea) — they are not rewritten to :3000. See docs/gitea.md.

Data lives on the host (bind mounts, not named volumes):

Path Contents
/opt/compose/tls Private CA + nginx server cert (owned by devops)
/opt/compose/middleware/data/rabbitmq RabbitMQ
/opt/compose/middleware/data/redis Redis AOF/RDB
/opt/compose/middleware/data/postgres PostgreSQL
/opt/compose/middleware/data/mongo MongoDB
/opt/compose/middleware/data/elasticsearch Elasticsearch
/opt/compose/devops/data/runner act_runner state
/opt/compose/devops/data/maven Reposilite
/opt/compose/devops/data/debian reprepro pool / dists / incoming
/opt/compose/devops/data/gitea Local Gitea (SQLite + repos)
/opt/compose/devops/data/debian-gpg APT signing key
/opt/compose/devops/data/registry Registry blobs
/opt/compose/devops/data/portainer Portainer

First deploy: Ansible creates host bind-mount dirs under /opt/compose/{devops,middleware}/data.

Deploy

Ansible runs in WSL. On Windows, ansible.ps1 wraps wsl make. Native Windows is not a supported control node.

Prerequisites: WSL with make + python3-venv, SSH key to darvik@devops.local, sudo on the target.

# WSL
sudo apt update && sudo apt install -y make python3-venv python3-pip
cd /mnt/d/Projects/devops/docker

Do not edit tracked inventory for secrets. make setup writes a gitignored .env (component toggles, credentials, optional CA paths); deploy targets read it via .env.yml + inventory/local.ini.

make setup          # components + secrets + optional bring-your-own CA
make ping
make docker         # Docker CE + Compose plugin
make devops         # TLS + registry/portainer/runner/…  (before middleware)
make middleware     # portal + data services
make deploy         # all of the above (site.yml)

Windows:

.\ansible.ps1 setup
.\ansible.ps1 ping
.\ansible.ps1 docker
.\ansible.ps1 devops
.\ansible.ps1 middleware
.\ansible.ps1 deploy

Other targets: make install, make check, make version, make clean, make help.

The Makefile uses project .venv and sets ANSIBLE_CONFIG / ANSIBLE_ROLES_PATH / ANSIBLE_INVENTORY (needed on world-writable /mnt/d/...).

Playbook issues a private CA + server cert, installs the CA into OS trust and /etc/docker/certs.d/ on devops.local, and does not use insecure-registries. LAN clients need the same CA (docs/registry-tls.md).

Portainer: user admin, password from .env (PORTAINER_PASSWORD, min 12 chars). --admin-password-file only seeds the first init. If login fails after a previous deploy, set PORTAINER_FORCE_REINIT=true once, make devops, then set it back to false (wipes Portainer data).

make devops issues TLS under /opt/compose/tls and brings up registry/portainer/runner/….

New portal card: add portal_services in inventory/group_vars/middleware.yml and, if needed, location = /status/... in stacks/middleware/nginx/default.conf.j2. Bilingual copy: portal_i18n + title / description { en, ru }.

Refresh screenshots (needs .env and a reachable portal; portal is forced to English):

npm install
npx playwright install chromium
PORTAL_URL=https://devops.local npm run screenshots

Cursor MCP:

{
  "mcpServers": {
    "gitea": {
      "url": "http://devops.local:8080/mcp",
      "headers": {
        "Authorization": "Bearer <gitea_mcp_access_token>"
      }
    }
  }
}

Variables

Credentials and host/URL overrides: .env (make setup). Defaults live in inventory/group_vars/ — do not put secrets there.

Variable Default Description
gitea_enabled false Local Gitea. .env: GITEA_ENABLED
runner_enabled / mcp_enabled / maven_enabled / debian_enabled true DevOps toggles
registry_enabled / portainer_enabled true Registry + Portainer (devops stack)
rabbitmq_enabled / redis_enabled / postgres_enabled / mongo_enabled / elastic_enabled true Middleware toggles
portal_lang en Portal default language (en / ru); UI toggle still works
tls_ca_source_crt / tls_ca_source_key `` Optional local CA paths (from make setup)
gitea_instance_url Synology URL Runner/MCP target. Not rewritten to local :3000
gitea_http_port / gitea_ssh_port 3000 / 2222 Local Gitea HTTP / SSH
gitea_root_url http://devops.local:3000/ Local server ROOT_URL only
gitea_runner_name devops.local Runner name in Gitea
gitea_runner_labels devops.local:docker://catthehacker/ubuntu:act-latest Runner labels
gitea_mcp_port 8080 Host port for gitea-mcp HTTP
maven_http_port 8083 Reposilite on localhost (nginx /maven/)
debian_http_port 8084 Debian www on localhost (nginx /debian/)
gitea_runner_force_reregister false Delete .runner and register again
middleware_http_port 80 Nginx HTTP → HTTPS redirect + /ca.crt
middleware_https_port 443 Nginx portal, UIs, registry /v2/
tls_enabled true Private CA + server cert for nginx
tls_extra_dns / tls_extra_ips [] Extra SANs on the server cert
rabbitmq_amqp_port 5672 RabbitMQ AMQP
rabbitmq_mqtt_port 1883 RabbitMQ MQTT (same plugins as iot-platform-go)
rabbitmq_mqtt_ws_port 15675 RabbitMQ MQTT over WebSocket
redis_port 6379 Redis
postgres_port 5432 PostgreSQL
mongo_port 27017 MongoDB
elastic_http_port 9200 Elasticsearch HTTP
elastic_java_opts -Xms512m -Xmx512m ES heap
compose_root /opt/compose Remote directory for stacks

Do not commit .env, .env.yml, or inventory/local.ini.

Adding a stack

  1. Add stacks/<name>/docker-compose.yml and .env.j2
  2. Add an inventory group and playbook that applies compose_stack with compose_stack_name: <name>

Troubleshooting

bcrypt / password_hash / __about__

Old passlib + bcrypt 5.x is incompatible. This repo hashes via scripts/bcrypt_hash.py. Reinstall venv deps:

make install
make middleware

No module named 'ansible.module_utils.six.moves'

Broken system Ansible. Use the Makefile venv only:

make clean
make install
make deploy

Gitea RunnerService/Declare 500

The runner keeps a hidden /opt/compose/devops/data/runner/.runner after first register. If the token was reset or the runner was removed in Gitea UI, Declare returns 500. Registration env vars are ignored while .runner exists.

ssh darvik@devops.local
sudo docker compose -f /opt/compose/devops/docker-compose.yml stop devops-runner
sudo rm -f /opt/compose/devops/data/runner/.runner
sudo docker compose -f /opt/compose/devops/docker-compose.yml up -d devops-runner

Or set GITEA_RUNNER_FORCE_REREGISTER=true once and make devops, then set it back to false. Use a fresh token from Gitea → Site Administration → Actions → Runners.

stacks not starting

ssh darvik@devops.local
sudo docker compose -f /opt/compose/devops/docker-compose.yml ps
sudo docker compose -f /opt/compose/devops/docker-compose.yml logs
sudo docker compose -f /opt/compose/middleware/docker-compose.yml ps
sudo docker compose -f /opt/compose/middleware/docker-compose.yml logs

Releases

Packages

Contributors

Languages