Repository navigation
RFC: replacement of server_environment #258
Description
RFC: replacement of server_environment
Authors:
Issues with server_environment we would like to fix
-
Reduce maintenance work: no more glue modules for every little field to be configured through env
-
Allow non-technical people to easily configure things directly in Odoo UI (e.g: test new mail server, sftp, etc)
-
Drop the hacky conversion to computed fields
-
It breaks the CLI neutralize queries (used in our platform and in Odoo.sh)
-
It can break core bussiness logic due to computed fields behaving differently
-
Explored alternatives
- Replacement with a module that encrypts fields directly in db
Too complicated. Even more complicated than the current solution. - Explore alternative without computed fields, like fetch
Still hacky and still requires lots of maintenance. - Replacement with an SQL-based entrypoint
Chosen solution. Described below.
Proposed solution
Inspired by the neutralize command, that executes raw SQL queries to clear credentials out from the database, we propose building a command line tool that writes environment-specific field values directly to the db. Essentially, this means preparing the database for the environment that’s gonna run on, and letting Odoo work on its own without any hacks.
The tool will only overwrite the credentials in the spec, but it will not worry about clearing them out. For that, we will rely directly on the neutralize command and we will encourage developers to include neutralization scripts on the modules that require them.
The idea is then to:
-
Configure production environments directly from the UI and stored in the db – purely standard, no added magic
-
Rely on the neutralization script to clear them out when restoring a db to a non-production environment.
-
Use the new tool to transform an input file/content set through the environment to SQL-queries, and set the environment-specific settings/credentials
This will be used to, for example, connect to a test sftp server instead. It will not be needed if we don’t want the test instance to connect to a specific server, though, as we will rely on neutralize to have it disabled anyway.
Packaging
This will be an external tool, not an Odoo module, that will work across Odoo versions.
Supported Odoo Versions
It must support Odoo >= 16.0, which is when neutralize was implemented.
The tool itself could be used to neutralize a list of model/fields by setting them to a falsy value, and so support previous versions too.
Input
The tool input will be a spec that defines the records and fields values to overwrite.
Originally we wanted to support a syntax similar to the one in the existing server_environment module: the ini format configuration files, using sections for model-wide settings and dotted notation for record-specific settings.
However, the global section name and the name field for record specific settings (tech_name) are defined in the module itself, and this would pose challenges for an implementation where this module is uninstalled, and so this information is missing.
Additionally, we may want to support smarter ways of targeting records, like with XML-ids or raw model names → we need a syntax that doesn’t require modifying the models’ schema
We will stick to ini format since it matches odoo.conf.
Examples:
# Model-wide settings (all records of this model)
# Section Syntax: [model:model_name]
[model:ir.mail_server]
smtp_port = 22
smtp_user = username
# Record settings using xml-id
# Section Syntax: [record:xml_id]
[record:customer_module.sftp_server]
sftp_port = 9999
sftp_user = username
# Additionally, config parameters can be set with
[config:set_param]
param.key = value1
another.parameter = value2
Note: camptocamp currently uses model-wide settings mainly in the following cases:
- outgoing_mail: setting mailpit everywhere
- incoming_mail: setting mailtrap everywhere
- printing server
- sometimes singleton backend records: can be migrated to xmlid
Output
The tool will transform each configuration section and value to raw SQL queries and execute them
Note: A pure SQL solution may be able to guess table and column names and work well in most cases, but it will fail to handle models with a custom _table (e.g.: ir.actions.actions → ir_actions instead of ir_actions_actions)
We may want to actually run the ORM for more accurate processing, though
Execution
For non-production environments, it must be executed after neutralize has ran, because we want our settings to not be cleared by it.
The way to run the script will probably depend on the way Odoo is deployed on your instances. We have some ideas about how to manage this in our deployments, but of course we welcome feedback for documenting a process that is streamlined with other's deployment usage.
Configuration
The production database must have all settings directly configured. No environment-specific settings.
All modules must have proper neutralization scripts. Check OCA and specific modules, trust Odoo to handle core modules.
The test environment databases will have production settings automatically cleared by neutralize, but will require environment-specific settings for things we want to persist.
Migration path from server_environment
Originally we wanted the transition to be effortless, by supporting the exact same syntax as server_environment.
However, this won’t be possible because some important information will be lost as soon as server_environment is uninstalled:
- The record’s tech_name, often used as IDs in the server env settings
*The model’s “section name” and “global section name”, also used to map settings to records
Nonetheless, the transition can be done manually and gradually, by supporting both modules to co-exist.
We are also thinking about trying to manage things in an uninstall hook. Something will be needed anyway because we need to get the columns back on the models for which some fields are no longer managed through server environment.
Next steps
- we have a POC for that tool
- discuss the idea with the OCA community
- list the OCA addons that have a direct dependency on server_environment that would need to be split to a glue module, create one issue per addon for the split
- find a smart and smooth migration path for these modules
- add things in the TODO list
Activity
petrus-v commentedon Mar 3, 2026
Thanks for sharing your plans.
Are you using
server_environment_data_encryption? What is your plan for this module? Do you think it's better to rely solely ondata_encryptionand stop storing keys for each environment in production?In fact, I'd love to see a new field (e.g., fields.Password) where we could set a passlib context similar to what SQLAlchemy-utils provides. This way, the secret key used to hash the password would only need to be set on each environment, and we could rely on this mechanism to inject the properly hashed value.
ivantodorovich commentedon Mar 4, 2026
Hello @petrus-v 👋🏻
In fact one of the things we want to avoid is having to maintain glue modules for every little field that must be set for differently by environment.
Heck, we don't even want to maintain an Odoo module for this. It'll be a command line utility that works on all supported versions.
The solution we have in mind is actually pretty simple.
For production environments, pure standard Odoo. Nothing special about it. Settings live in the database. Everything can be configured directly from the UI.
For other environments (dev, integration, etc), we must ensure databases go through the following two steps before running Odoo:
The neutralization step makes the db safe, by disabling any external interface connections. For it to work, modules must actually implement the neutralization queries. It becomes critical that we do that.
The configuration step is optional, in fact. Without it, you'd get exactly the same behavior than in Odoo.sh: a neutralized database with disabled and unconfigured interfaces, that you must manually reconfigure. It's this step that our new tool will solve, in order to make it easy to have environment-specific settings that live in an external configuration file and can survive the mandatory neutralization step.
thomaspaulb commentedon Mar 4, 2026
In our setup we don't use
server_environment, instead we have a wrapper script that copy production to testing, which calls neutralization but also does all kinds of other things.One of these "things" is a concept that might also be considered here - in the production environment, if you have an
ir.config.parameterkey such assome_app_passwordthat you wish to be replaced with something else in the testing environment, you craft another key, something like_testing_some_app_password, and then in the testing environment, thesome_app_passwordkey will be replaced with the content of the other key.While our system is restricted to
ir.config.parameterrecords I could imagine a new module that extends this concept to be able to replace database fields from any model with other values as well. So such a module would eg:So in short, the concept is, "Storing environment-specific values not in an external file but in the production database"
sbidoul commentedon Mar 4, 2026
Hi, thanks for sharing, this sounds super interesting!
A few thoughts / question after a first quick read.
Since the file format has to change, would you consider using something like toml which makes it easier to handle multiline values and would be amenable to schema validation?
There are some modules which import
serv_configdirectly, for server-wide non-database related configuration (e.g. queue_job). Need to think about this. This can probably be replaced by something else (environment variables likely), although the multi-layer config of server_environment is nice to have (which can also be handled in deployment pipelines).Would there be anything preventing the use of this system on the production environment too?
We have use cases where we like to ship some base prod configuration to reduce the risk of errors by downstream sysadmins handling the deployment.
In that scenario, the multi-layer merged configuration system (base + env + odoo.cfg) is nice too. Would that still exist?
Where would the configurations be read from?
I have seen issues with concurrent runs of odoo neutralize (hence acsone/click-odoo-contrib#178). There could be similar issues with this that require special attention?
server_env prevents the user from changing environment-managed settings. Sometimes it is desired, sometimes not. Would this need a mechanism to record that the config has already been applied on a production copy, to avoid reapplying it, in order to preserve user changes in that environment?
vincent-hatakeyama commentedon Mar 4, 2026
Thank you for taking the time to look into this.
We also use server_environment, including in odoo.sh in a specific instance.
It is used in production for several reasons, including:
This is why we developed server_environment_autocreate.
Some of the parameters are purely technical in nature and needs to be done ASAP, for example, to set up the default storage with fs_attachment.
When copying the database from a production server to a testing one, on top of neutralization, an SQL script is also used. This is usually used to re-enable some SSO (auth_saml/auth_oidc) or to clean up some tables.
On one Odoo.sh project, we use server_environment to change a couple of configuration to setup some configuration parameters on the staging environment. The production is left as is. This means that the code of the project need to be updated if the parameters needs changing. The production parameters can be changed by the customer as needed.
hparfr commentedon Mar 5, 2026
That's one of our main concerns. That's why we use server_env_data_encryption. Having something secure at rest is really really good.
It's not only leaking secrets, it's also forbid sending email or sending e-invoice or whatever from a dev or test environment wich has not been properly neutralized.
I suggest to add a fail safe mechanism in your proposal. For instance, an odoo module should be present in the path in order to raise during the boot if neutralization has not be done if env is not in prod.
What are our (Akretion) needs:
nth: nice to have
The secure at rest feature was initialy (odoo v8) in a separate module.
ivantodorovich commentedon Mar 5, 2026
Hey guys, thanks for the interest and the replies!
I'll try to reply to each point.
@thomaspaulb
That's sort of what we have in mind, except we plan to call neutralization + configuration* in an entrypoint.
We call configuration the step that does, like you said, all kinds of other things
We plan to package a tool that transforms this into executed SQL queries:
@sbidoul
Yeap, I think that's a good idea
You're talking about this lazy dependency on
server_environment: https://github.com/OCA/queue/blob/1ea2c454c8452b59ac27a24a0699bf7279a223f1/queue_job/jobrunner/__init__.py#L12-L20 -- Personally, I didn't know about itWe already use environment variables to setup queue job. I believe every setting has an environment variable defined.
Nope, there would be nothing preventing this.
We plan to package a tool that parses the configuration and executes the necessary queries to configure the database.
The tool will then be executed in an entrypoint step of our docker image. It can be executed as many times as needed and read from different sources.
We currently use two environment variables with
server_environment:SERVER_ENV_CONFIGandSERVER_ENV_CONFIG_SECRET. We plan to do something similar with this.Imagine something like this:
You'll have the freedom to use it however you like
Indeed, that's a good point.
This new tool must also acquire a lock
We plan to do something similar to what
neutralizedoes: create anir.config_parameterupon execution.Then, we can simply skip the configuration step in the entrypoint if the database has already been configured, allowing changes to survive restarts.
We actually do the same for the neutralization step. We only execute it if the
database.is_neutralizedis missing, preventing subsequent neutralizations on simple restarts.@hparfr
We plan to solve this directly at our docker image level, but yes -- you're absolutely right.. and the Odoo module idea sounds safer.
We have similar needs, but perhaps different priorities at the moment.
We plan to sacrifice the secure at rest item for the sake of simplicity. Converting regular stored fields to computed ones is a bit hacky and causes issues and maintenance burden we'd like to avoid. We've considered other alternatives but we settled for this one, which we feel it's more aligned to upstream Odoo.
sbidoul commentedon Mar 6, 2026
@ivantodorovich sounds good.
Would you keep
server_environment_fileto have the capability to merge multiple configs (base from server_environment_file + env from server_environment_file + SERVER_ENV_CONFIG + SERVER_ENV_CONFIG_SECRET) ?Another thing we sometimes use is the capability to set odoo.cfg values from server_environment_file. I'd need to check but this was sometimes useful, for instance to configure the sentry module which was reading its config from
tools.config.misc.yankinmax commentedon Mar 25, 2026
Hello @gurneyalex @ivantodorovich @sbidoul @lmignon
I've started to open PR's to make a split for following modules starting Odoo >= 16.0:
fs_storageimage_tagstorage_backendI've tried to upgrade splitted
fs_storagealongside withfs_storage_environmentwithauto_install: Trueon the 19.0 project.fs_storage_environmentis not automatically installed, so we need to provide a migration script.I'll write a generic script and test it on v19.
I've started to receive a feedback on this topic.
Can we pls continue discussion here and decide the better way to handle this change?
lmignon commentedon Mar 25, 2026
Regarding the need for change management for data managed by server_environment. I think we could put in place a generic way to prevent modification by any users except those part of a new group.... The idea is to create an abstract model where we implement the
_register_hookmethod (the one called when the registry is loaded). The deployment tool used to populate the database with the values from the env files should also store into the database the resolved conf file or a description of the model / instance and fields managed by the env files .Into the _register_hook, for each model for which there are records containing fields managed by the server environment, we could patch the
read,writeandunlinkmethods to check if the record impacted is one managed by server env and if the field is also one managed by server env (we can store on the class a structure with the required information specific to this model computed from the data provided by the deployment tool)... In this way, the check only occurs on models where some records are managed by server envs, the check is done at the top of the call stack and we can add a special security group to allow modification from within odoo....ivantodorovich commentedon Mar 31, 2026
@lmignon that could indeed be an improvement in
server_environment, but the approach we want to take is to completely get rid of it for the sake of simplicity, knowingly sacrificing features that I understand are very important for others.@yankinmax started working on removing the hard dependency of some modules, like
fs_storage, targetting 16.0+ for now. Regardless of the path we or others take, we believe theserver_environmentdependency should not be enforced -- and that's not currently the case for some very important modules. I hope we can agree on this. (e.g: OCA/storage#580, OCA/web-api#101)Meanwhile, @gurneyalex is experimenting with uninstall hooks to offer a "clean way out" of
server_environment. Still in draft:sbidoul commentedon Sep 22, 2026
@ivantodorovich is your configuration tool ready for prime time already?
I'm considering to integrate it in
click-odoo-update, so it can run under the same advisory lock as the update and neutralization.ivantodorovich commentedon Sep 22, 2026
It's still in POC phase. We are in the process of migrating some projects to it, now that the fs_storage split was merged, but it's not live in any production project so far.
We are using the tool like this: https://github.com/camptocamp/docker-odoo-project/blob/main/start-entrypoint.d/003_confidoo_apply.
And it goes hand-in-hand with https://github.com/camptocamp/docker-odoo-project/blob/main/start-entrypoint.d/002_neutralize (ran right before)
Maybe we'll move some of that to the tool itself at some point, through optional parameters. Like storing an ir.config_parameter when it's applied, and skipping it db is already "configured".