Skip to content

RFC: replacement of server_environment #258

Open

Description

@gurneyalex

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

  1. Replacement with a module that encrypts fields directly in db
    Too complicated. Even more complicated than the current solution.
  2. Explore alternative without computed fields, like fetch
    Still hacky and still requires lots of maintenance.
  3. 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

  1. petrus-v commented on Mar 3, 2026

    @petrus-v
    Contributor

    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 on data_encryption and 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.

  2. ivantodorovich commented on Mar 4, 2026

    @ivantodorovich
    Contributor

    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:

    • neutralization: clear environment-specific settings and credentials from the db
    • configuration: apply settings and credentials for this environment, directly in the db

    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.

  3. thomaspaulb commented on Mar 4, 2026

    @thomaspaulb

    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.parameter key such as some_app_password that 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, the some_app_password key will be replaced with the content of the other key.

    While our system is restricted to ir.config.parameter records 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:

    • Offer a UI to define your different environments
    • Offer a UI to define which model fields can be replaced by test values
    • Offer a UI to define test values that apply to single or all environments
    • Include a well-crafted neutralize.sql which applies all of the above upon neutralization

    So in short, the concept is, "Storing environment-specific values not in an external file but in the production database"

  4. sbidoul commented on Mar 4, 2026

    @sbidoul
    Member

    Hi, thanks for sharing, this sounds super interesting!

    A few thoughts / question after a first quick read.

    ini file format

    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?

    server-wide configurations

    There are some modules which import serv_config directly, 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).

    The production database must have all settings directly configured. No environment-specific settings.

    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?

    concurrency

    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?

    user updates

    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?

  5. vincent-hatakeyama commented on Mar 4, 2026

    @vincent-hatakeyama
    Contributor

    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:

    1. avoid error by admin users (in Odoo) that should not change a setting.
    2. so that sysadmin (the one that deploy), do not need to have the rights to go into Odoo to configure something.
      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.
    3. Database backups does not contain the secrets and can be given to developers with less worry. (mainly that they forget to neutralize / pass a script on the database).

    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.

  6. hparfr commented on Mar 5, 2026

    @hparfr
    Contributor

    Database backups does not contain the secrets and can be given to developers with less worry. (mainly that they forget to neutralize / pass a script on the database).

    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:

    1. setup from UI
    2. setup from config files (nth)
    3. secure at rest (no secrets in clear in the db)
    4. ensure neutralization if not in prod
    5. replace credentials within a record (nth)
    6. having different values for different environments (nth)

    nth: nice to have

    The secure at rest feature was initialy (odoo v8) in a separate module.

  7. ivantodorovich commented on Mar 5, 2026

    @ivantodorovich
    Contributor

    Hey guys, thanks for the interest and the replies!
    I'll try to reply to each point.

    @thomaspaulb

    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.

    [...]

    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:

    # Model-wide updates
    # e.g: Disable all scheduled actions
    [model:ir.cron]
    active = False
    
    # Update specific record (targeted by XML-ID)
    [record:base.partner_admin]
    name = Admin
    email = admin@example.com
    
    # Set system parameters
    [config:set_param]
    ribbon.name = Test Environment
    database.uuid = 0000-0000-0000-0000

    @sbidoul

    ini file format
    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?

    Yeap, I think that's a good idea

    server-wide configurations

    There are some modules which import serv_config directly, 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).

    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 it

    We already use environment variables to setup queue job. I believe every setting has an environment variable defined.

    The production database must have all settings directly configured. No environment-specific settings.

    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.

    Nope, there would be nothing preventing this.

    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?

    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_CONFIG and SERVER_ENV_CONFIG_SECRET. We plan to do something similar with this.

    Imagine something like this:

    # File argument
    config-apply config.ini
    
    # Pipe from stdin
    config-apply < config.ini
    
    # Environment variable
    echo $ENV_CONFIG | config-apply
    echo $ENV_CONFIG_SECRET | config-apply

    You'll have the freedom to use it however you like

    concurrency

    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?

    Indeed, that's a good point.
    This new tool must also acquire a lock

    user updates

    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?

    We plan to do something similar to what neutralize does: create an ir.config_parameter upon 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_neutralized is missing, preventing subsequent neutralizations on simple restarts.


    @hparfr

    Database backups does not contain the secrets and can be given to developers with less worry. (mainly that they forget to neutralize / pass a script on the database).

    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.

    We plan to solve this directly at our docker image level, but yes -- you're absolutely right.. and the Odoo module idea sounds safer.

    What are our (Akretion) needs:

    1. setup from UI
    2. setup from config files (nth)
    3. secure at rest (no secrets in clear in the db)
    4. ensure neutralization if not in prod
    5. replace credentials within a record (nth)
    6. having different values for different environments (nth)

    nth: nice to have

    The secure at rest feature was initialy (odoo v8) in a separate module.

    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.

  8. sbidoul commented on Mar 6, 2026

    @sbidoul
    Member

    @ivantodorovich sounds good.

    Would you keep server_environment_file to 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.

  9. yankinmax commented on Mar 25, 2026

    @yankinmax

    Hello @gurneyalex @ivantodorovich @sbidoul @lmignon
    I've started to open PR's to make a split for following modules starting Odoo >= 16.0:

    • fs_storage
    • image_tag
    • storage_backend

    I've tried to upgrade splitted fs_storage alongside with fs_storage_environment with auto_install: True on the 19.0 project.
    fs_storage_environment is 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?

  10. lmignon commented on Mar 25, 2026

    @lmignon
    SponsorContributor

    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_hook method (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, write and unlink methods 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....

  11. ivantodorovich commented on Mar 31, 2026

    @ivantodorovich
    Contributor

    @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 the server_environment dependency 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:

  12. sbidoul commented on Sep 22, 2026

    @sbidoul
    Member

    @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.

  13. ivantodorovich commented on Sep 22, 2026

    @ivantodorovich
    Contributor

    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".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions