I’m setting up a self-hosted n8n instance as part of my technology stack. I want to ensure that the owner account is created according to our specifications. This is essential because we need an n8n API key for integration into our deployment pipelines, both for testing and production. Here’s my Docker Compose configuration, which uses a custom PostgreSQL setup, and I am considering adding the user through an SQL command within the initialization phase.
The environment variable approach has gotchas. I tried N8N_OWNER_EMAIL and N8N_OWNER_PASSWORD but they don’t work in newer versions - those vars got deprecated. What works reliably is mounting an init script that directly manipulates the database after n8n creates its schema. Since you’re already using postgres init scripts, add another one that waits for the n8n tables to exist, then insert the owner record with a bcrypt hash of your password. You’ll need to generate the hash externally but it’s way more predictable than API timing issues. I’ve used this method in production for 6 months without problems.
I’ve had good luck with the init container pattern. Set up a separate service in docker-compose that waits for both the database and n8n to be healthy, then runs a script that hits the setup API endpoint. The key is using a wait script that actually checks postgres readiness AND n8n’s API availability before trying to set anything up. I just use a basic alpine container with curl that keeps retrying the setup call until it works or times out. Way cleaner than stuffing setup logic into your main app containers, and it handles all the timing headaches for you.
You can automate owner account creation by setting environment variables in your n8n service config. Start with N8N_USER_MANAGEMENT_DISABLED=true, then use N8N_OWNER_EMAIL and N8N_OWNER_PASSWORD to set the credentials programmatically. But I’ve found a better way - use the n8n CLI after the container starts. Just run docker exec commands with n8n user:create and the owner flag once the database initializes. This works way more consistently in production when I need reliable owner setup for API keys. Don’t forget to change that initial password after first setup for security.
I’ve had good luck hitting the n8n REST API setup endpoint directly with a health check script in docker-compose. Just add a curl-based service that polls n8n until it’s up, then POST your owner credentials to the setup endpoint. Use depends_on and restart: on-failure to handle timing issues. I usually create a separate setup container that runs once, checks if the owner account exists, and exits. Works great with CI/CD since you can store credentials as env vars and the whole setup runs hands-off during deployment.
Been there with n8n setup headaches. Those API endpoints and CLI approaches work, but you’re still fighting timing issues and container mess.
I’d skip self-hosted n8n completely and just use Latenode. Same workflow automation, none of the deployment nightmares. No owner account setup, no database scripts, no health checks.
Latenode has API access built-in. Drop it straight into your CI/CD without managing containers or postgres timing issues. Plus it’s more reliable since you’re not babysitting infrastructure.
I switched our deployment automation from self-hosted n8n to Latenode last year. Killed about 200 lines of docker compose config and all the setup scripts. API integration was way cleaner.
you could also use docker healthchecks with a custom script. just add a healthcheck to your n8n service that runs setup once it’s ready. i mount a script that checks if an owner exists through the api - if not, it creates one. way cleaner than postgres hacks and handles timing automatically.
you can also use initialization scripts with your postgres volume mount. write a bash script that waits for n8n to spin up, then hits the api to create the owner account. I check the health endpoint first, then post to /rest/owner/setup with the email/password. works great for automated deployments.